package com.authine.cloudpivot.ext.service.settle.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.cola.dto.RequestContext;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.Enum.*;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.constants.PlatformConst;
import com.authine.cloudpivot.ext.dto.base.Ids;
import com.authine.cloudpivot.ext.dto.form.InvoiceApplyForm;
import com.authine.cloudpivot.ext.dto.model.bill.Bill;
import com.authine.cloudpivot.ext.dto.model.contract.ContractWriteOffRecord;
import com.authine.cloudpivot.ext.dto.model.invoice.ApplyInvoiceDetailDto;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceApply;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceDetailBill;
import com.authine.cloudpivot.ext.dto.model.settle.*;
import com.authine.cloudpivot.ext.dto.model.trade.Trade;

import com.authine.cloudpivot.ext.dto.query.SettleApplyQuery;
import com.authine.cloudpivot.ext.dto.system.UserDto;
import com.authine.cloudpivot.ext.service.settle.SettleService;
import com.authine.cloudpivot.ext.service.voucher.KingDeeFinanceService;
import com.authine.cloudpivot.ext.service.voucher.impl.KingDeeFinanceServiceImpl;
import com.authine.cloudpivot.ext.utils.*;
import com.authine.cloudpivot.ext.utils.kingdee.DateUtils;
import com.authine.cloudpivot.ext.utils.system.UserUtils;
import com.authine.hermes.app.launcher.service.WorkflowService;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
public class SettleServiceImpl implements SettleService {

    protected WorkflowService workflowService = (WorkflowService) ApplicationContextUtils.getBean(WorkflowService.class);

    KingDeeFinanceService kingDeeFinanceService = new KingDeeFinanceServiceImpl();

    @Override
    public Settle loadById(String id) {
        return JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*").eq("id", id).queryForPOJO(Settle.class);
    }

    @Override
    public List<Settle> loadListByIds(List<String> ids) {
        return JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*").in("id", ids).queryForPOJOList(Settle.class);
    }

    @Override
    public String createAdvanceSettle(SettleInvoice settleInvoice) {
        //当付款方式选择现金时，收款账号默认为18个0
        SettleType type = settleInvoice.getType();
        if (type == SettleType.Money) {
            settleInvoice.setSale_bank_no("000000000000000000");
            settleInvoice.setSale_bank_info("现金");
            settleInvoice.setSale_bank_account("现金");
            settleInvoice.setSale_phone("00000000");
        }
        verifyCreate(settleInvoice);
        Assert.isTrue(settleInvoice.getConfirm_time() != null, "收款时间不能为空");

        if (settleInvoice.getBusiness_type().equals(SettleBusinessType.SaleReceivable)) {
            Assert.notNull(settleInvoice.getPurchase_name(), "付款组织抬头不能为空");
        }
        Assert.isTrue(RegexUtils.notNull(settleInvoice.getPurchase_organization_name()) || !ObjectUtils.isEmpty(settleInvoice.getPurchase_organization_id()), "付款组织信息不能为空");

        if (settleInvoice.isContract()) {
            Assert.notNull(settleInvoice.getContract_payment_type(), "代购收款类型不能为空");
        }

        Settle settle = new Settle();
        BeanUtils.copyProperties(settleInvoice, settle);
        settle.setWrite_off_total(settleInvoice.getTotal())
                .setWoffNow("0")
                .setRefund_total(BigDecimal.ZERO)
                .setStatuss(SettleStatus.Done)
                .setApply_time(new Date())
                .setRefund_total(BigDecimal.ZERO)
                .setPayment_time(settleInvoice.getConfirm_time());
        String purchaseName = settle.getPurchase_name();
        if (null != purchaseName) {
            purchaseName = purchaseName.replace("(", "（").replace(")", "）");
            settle.setPurchase_name(purchaseName);
        }

        //收款的是平台，操作者角色是平台，就是已付款状态
//        if (PlatformConst.PLATFORM_ORGANIZATION_IDS.contains(settle.getSale_organization_id().getId())
//                && settle.getBusiness_type().equals(SettleBusinessType.SaleReceivable.name())
//                && RoleUtils.existByUserIdAndRoleName(RequestContext.getCorpLoginId(), PlatformConst.ROLE_PM_ADMIN)) {
//            settle.setStatuss(SettleStatus.Done);
//        }
        if(settle.getBusiness_type().equals(SettleBusinessType.SaleReceivable.name())){
            settle.setPlatform_organization_id(settle.getSale_organization_id().getId());
        }

        SingleResponse<BO> bo = BoServiceUtils.createBo(ModelConst.T_SETTLE, Collections.singletonList(settle.beanToMap()));

        // 凭证部分,金蝶创建预收/付款
        Settle settleData = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField(" * ").eq("id", bo.getData().getBizObjectId()).queryForPOJO(Settle.class);
        settleData.setContract(settleInvoice.isContract()).setContract_payment_type(settleInvoice.getContract_payment_type());
        List<String> data = new ArrayList<>();
        data.add("3313");
        data.add("3463");
        data.add("3462");
        /*** 以前代购的(目前就上海志豪实业有限公司和上海凯科管业科技股份有限公司和上海凯科阀门制造有限公司)，没有走转采的，用代购收款单核销不了，需要用普通订单类型，但是又需要生成代购凭证，这里做特殊处理，数据走完后删除 ***/
        if (data.contains(settleInvoice.getPurchase_organization_id().getId())){
            settleData.setContract(true);
        }
        kingDeeFinanceService.createAdvanceSettle(settleData);
        return bo.getData().getBizObjectId();
    }

    @Override
    public void cancel(String id) {
        Settle settle = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .eq("id", id).queryForPOJO(Settle.class);
        Assert.notNull(settle, "未查询到要作废的结算单");
        Assert.isNull(settle.getReference_id(), "退款单不能作废");
        Assert.isTrue(settle.getStatuss() != SettleStatus.Returned, "已作废结算单不能再次作废");
        Assert.isTrue(settle.getRefund_total().compareTo(BigDecimal.ZERO) == 0, "产生退款的结算单不能作废");
        Assert.isTrue(settle.getTotal().subtract(settle.getWrite_off_total()).compareTo(BigDecimal.ZERO) == 0, "已核销完成结算单不能作废");
        MapBuilder mapBuilder = MapBuilder.create(new HashMap<String, Object>())
                .put("id", settle.getId())
                .put("statuss", SettleStatus.Returned.name());
        BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, mapBuilder.build());

        // 删除金蝶付款凭证
        kingDeeFinanceService.deleteAdvanceSettle(id);
    }

    @Override
    public void refund(SettleRedInvoice settleRedInvoice, Settle settleReceive) {
        SettleBusinessType settleBusinessType = SettleBusinessType.PurchaseReceivable;
        if (SettleBusinessType.SaleReceivable.name().equals(settleReceive.getBusiness_type())) {
            settleBusinessType = SettleBusinessType.SalePayment;
        }
        Settle settleRefund = new Settle();
        BeanUtils.copyProperties(settleRedInvoice, settleRefund);
        settleRefund.setReference_id(settleReceive.getId())
                .setStatuss(SettleStatus.Approving)
                .setBusiness_type(settleBusinessType)
                .setApply_time(new Date())
                .setWrite_off_total(settleRedInvoice.getTotal())
                .setWoffNow(settleRefund.getWrite_off_total().compareTo(BigDecimal.ZERO) > 0 ? "0" : "1")
                .setPurchase_name(settleRedInvoice.getPurchase_name());
        if (SettleBusinessType.SaleReceivable.name().equals(settleReceive.getBusiness_type())){
            settleRefund.setPlatform_organization_id(settleReceive.getSale_organization_id().getId());
        }else{
            settleRefund.setPlatform_organization_id(settleReceive.getPurchase_organization_id().getId());
        }
        Map<String, Object> param =  settleRefund.beanToMap();
        BoServiceUtils.createBo(ModelConst.T_SETTLE, Collections.singletonList(param));

        //回写原收款单退款金额
        settleReceive.setRefund_total(getSettleRefundTotal(settleReceive.getId()));
        settleReceive.setWrite_off_total(getSettleWriteOffAmount(settleReceive.getId()));

        param.clear();
        param.put("id", settleReceive.getId());
        param.put("write_off_total", settleReceive.getWrite_off_total());
        param.put("refund_total", settleReceive.getRefund_total());
        param.put("woffNow", settleReceive.getWrite_off_total().compareTo(BigDecimal.ZERO) > 0 ? "0" : "1");
        BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, param);
    }

    @Override
    public void refundConfirm(List<String> settleIds) {
        List<Settle> settleEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField(" * ")
                .in("id", settleIds)
                .eq("statuss", SettleStatus.Approving.name())
                .queryForPOJOList(Settle.class);
        Assert.notEmpty(settleEntityList, "未查询到待确认退款的结算单信息");

        MapBuilder<String, Object> updateParam = MapBuilder.create(new HashMap<>());
        for (Settle settleEntity : settleEntityList) {
            updateParam.map().clear();
            updateParam.put("id", settleEntity.getId())
                    .put("statuss", SettleStatus.Done.name())
                    .put("confirm_member_id", RequestContext.getCorpLoginId())
                    .put("confirm_member_name", RequestContext.getLoginRealName())
                    .put("confirm_time", DateUtils.dateToStr(new Date(), DateUtils.FORMAT_PATTERN_DATETIME));

            BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, updateParam.build());

            //更新交易记录的可结算金额
            updateTradeAllowSettleAmount(settleEntity);

        }

        organizationAccountService.refundByPayment(settleIds);
        // 凭证部分
        List<Settle> settleKingDeeList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField(" * ")
                .in("id", settleIds)
                .eq("statuss", SettleStatus.Approving.name())
                .queryForPOJOList(Settle.class);
        kingDeeFinanceService.refundConfirm(settleKingDeeList);

    }

    @Override
    public void refundCancel(List<String> settleIds) {
        List<Settle> settleEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField(" * ")
                .in("id", settleIds)
                .in("statuss", Arrays.asList(SettleStatus.Done.name(), SettleStatus.Approving.name()))
                .queryForPOJOList(Settle.class);
        Assert.notEmpty(settleEntityList, "请确认当前退款单状态");
        List<Settle> list = new ArrayList<>();//记录已付款的退款单，已付款需要删除凭证
        settleEntityList.stream().forEach(settle -> {

            if (settle.getStatuss() == SettleStatus.Done) {
                list.add(settle);
            }
            JdbcTemplateUtils.builder(ModelConst.T_SETTLE)
                    .putFieldAndVal("statuss", SettleStatus.Returned.name())
                    .eq("id", settle.getId())
                    .update();

            //更新原结算单退款金额
            BigDecimal refundTotal = getSettleRefundTotal(settle.getReference_id());
            //更新原结算单可核销金额 write_off_total
            BigDecimal writeOffAmount = getSettleWriteOffAmount(settle.getReference_id());
            JdbcTemplateUtils.builder(ModelConst.T_SETTLE)
                    .putFieldAndVal("write_off_total", writeOffAmount)
                    .putFieldAndVal("refund_total", refundTotal)
                    .eq("id", settle.getReference_id())
                    .update();

        });
        // 删除金蝶付款凭证
        kingDeeFinanceService.refundCancel(list);

    }

    @Override
    public void settlePurchasePayment(List<SettlePayment> paymentList) {
        List<String> settleIds = paymentList.stream().map(SettlePayment::getId).distinct().collect(Collectors.toList());
        //获取选中的结算单信息
        List<Settle> settleEntityList = this.loadListByIds(settleIds);
        Assert.notEmpty(settleEntityList, "结算单不存在");

        //采购付款单和待财务审批付款，否则不能付款
        Set<Settle> settleEntitySet = settleEntityList.stream().filter(t ->!SettleStatus.Approving.name().equals(t.getStatuss().name())).collect(Collectors.toSet());
        Assert.isTrue(CollectionUtils.isEmpty(settleEntitySet), "结算单状态不是待财务审批付款");
        settleEntitySet = settleEntityList.stream().filter(t -> !SettleBusinessType.PurchasePayment.name().equals(t.getBusiness_type())).collect(Collectors.toSet());
        Assert.isTrue(CollectionUtils.isEmpty(settleEntitySet), "结算单不是采购付款单");

        List<Settle> settleList = new ArrayList<>();
        List<String> writeBackTradeIds = new ArrayList<>();

        for (Settle settleEntity : settleEntityList) {
            List<SettleDetail> settleDetailEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                    .eq("settle_id", settleEntity.getId())
                    .queryForPOJOList(SettleDetail.class);

            Assert.isTrue(!CollectionUtils.isEmpty(settleDetailEntityList), "该付款单未核销，不能付款");
            Assert.isTrue(BigDecimalUtils.sub(settleEntity.getTotal(), settleEntity.getRefund_total() == null ? BigDecimal.ZERO : settleEntity.getRefund_total()).compareTo(BigDecimal.ZERO) > 0,
                    "此结算单已经全部退款，不需要付款");

            List<SettlePayment> settlePaymentList = paymentList.stream().filter(t -> t.getId().equals(settleEntity.getId())).collect(Collectors.toList());
            Assert.isTrue(!CollectionUtils.isEmpty(settlePaymentList), "付款操作整理付款信息异常");
            SettlePayment payment = settlePaymentList.get(0);

            settleEntity.setType(payment.getType())
                    .setType(payment.getType())
                    .setPurchase_bank_info(payment.getBank_info())
                    .setPurchase_bank_no(payment.getBank_no())
                    .setPurchase_bank_account(payment.getBank_ccount())
                    .setPurchase_phone(payment.getPhone())
                    .setConfirm_member_id(RequestContext.getCorpLoginId())
                    .setConfirm_member_name(RequestContext.getLoginRealName())
                    .setPayment_time(payment.getPayment_time())
                    .setStatuss(SettleStatus.Done)
                    .setConfirm_time(new Date());

            //因生成服务费时机往前调整，所以付款时再确认一次
            BigDecimal platform = CalculatorUtils.sum(settleDetailEntityList, BiFunctionConst.settleDetailPlatformFun);
            BigDecimal interest = CalculatorUtils.sum(settleDetailEntityList, BiFunctionConst.settleDetailInterestFun);
            if (PlatformConst.PLATFORM_ORGANIZATION_IDS.contains(settleEntity.getPurchase_organization_id().getId())) {
                if (platform.compareTo(BigDecimal.ZERO) > 0 || interest.compareTo(BigDecimal.ZERO) > 0) {
                    Set<String> settleDetailIdcollect = settleDetailEntityList.stream().map(SettleDetail::getId).collect(Collectors.toSet());
                    List<BillType> billTypes = new ArrayList<>();
                    billTypes.add(BillType.FinancialFee);
                    billTypes.add(BillType.PlatformFee);
                    List<Bill> billFeeEntityList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                            .in("reference_id", settleDetailIdcollect)
                            .in("type", billTypes)
                            .queryForPOJOList(Bill.class);

                    //如果没有生成服务费账单，就再生成一次
                    if (CollectionUtils.isEmpty(billFeeEntityList)) {
                        //如果是平台采购付款，就要生成对应服务费账单和服务费发票
                        if (BigDecimalUtils.add(platform, interest).compareTo(BigDecimal.ZERO) > 0) {
                            List<String> serviceFeeInvoiceIds = this.generateServiceFeeBill(settleEntity.getId());
                            if (!CollectionUtils.isEmpty(serviceFeeInvoiceIds)) {
                                settleEntity.setInvoice_service_ids(String.join(",", serviceFeeInvoiceIds));
                            }
                        }
                    }
                }
            }
            settleEntity.setInterest(interest).setPlatform(platform);
            BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, settleEntity.beanToMap());

            //需要回写的交易ID
            Set<String> tradeIds = settleDetailEntityList.stream().map(SettleDetail::getTrade_id).collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(tradeIds)) {
                writeBackTradeIds.addAll(tradeIds);
            }

            //金蝶凭证使用
            settleEntity.setSettleDetailList(settleDetailEntityList);
            settleList.add(settleEntity);
        }

        //回写交易的结算状态和结算单ID
        this.writeBackTrade(writeBackTradeIds);

        //信用额度
        List<String> idList = paymentList.stream().map(SettlePayment::getId).distinct().collect(Collectors.toList());
        organizationAccountService.saveByPayment(idList, 1);

        //凭证部分
        kingDeeFinanceService.settlePurchasePayment(settleList);
        //applicationEventPublisher.publishEvent(new KingDeeApplicationEvent(KingDeeSettleEvent.settlePurchasePayment(settleList)));
    }

    @Override
    public String paymentCannel(List<String> settleIds) {
        List<Settle> settleList = new ArrayList<>();
        List<String> settleCloseIdList = new ArrayList<>();//记录要取消凭证的结算ID
        StringBuffer result = new StringBuffer();
        List<Settle> settleEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .in("id", settleIds)
                .queryForPOJOList(Settle.class);
        for (Settle settleEntity : settleEntityList) {
            Assert.isTrue(settleEntity.getStatuss() == SettleStatus.Done, "只有" + SettleStatus.Done.des + "状态的结算单才能取消");
            Assert.isTrue(settleEntity.getRefund_total() == null || settleEntity.getRefund_total().compareTo(BigDecimal.ZERO) == 0, "已产生退款的结算单不能取消付款");

            settleEntity.setStatuss(SettleStatus.Approving);
            BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, settleEntity.beanToMap());

            result.append("</br>结算单").append(settleEntity.getId()).append("取消付款成功。");
            if (settleEntity.getStatuss() == SettleStatus.Done
                    || settleEntity.getStatuss() == SettleStatus.Approving
                    || settleEntity.getStatuss() == SettleStatus.ApprovingFinance) {
                settleCloseIdList.add(settleEntity.getId());
            }
            settleList.add(settleEntity);
        }
        this.deleteBillServiceAndCloseServiceInvoice(settleCloseIdList, result);

        // 取消付款删除凭证
        //applicationEventPublisher.publishEvent(new KingDeeApplicationEvent(KingDeeSettleEvent.close(settleList)));
        kingDeeFinanceService.close(settleList);

        organizationAccountService.saveByPayment(new ArrayList<>(settleIds), 0);
        return result.toString();
    }

    /**
     * 删除服务费账单并且关闭服务费发票
     * 获取服务费发票，服务费发票待开票，就直接删除，已开票的给提示
     *
     * @param settleIdList 结算单编号列表
     * @param result       提示语句
     * @return
     */
    private void deleteBillServiceAndCloseServiceInvoice(List<String> settleIdList, StringBuffer result) {
        if (!CollectionUtils.isEmpty(settleIdList)) {
            //获取服务费发票，服务费发票待开票，就直接删除，已开票的给提示
            List<InvoiceApply> invoiceApplyEntityList = new ArrayList<>();
            //结算明细
            List<SettleDetail> settleDetailEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                    .in("settle_id", settleIdList)
                    .queryForPOJOList(SettleDetail.class);
            //结算明细对应服务费的账单
            List<String> referenceIds = settleDetailEntityList.stream().map(SettleDetail::getId).collect(Collectors.toList());
            List<Bill> billList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                    .in("reference_id", referenceIds)
                    .queryForPOJOList(Bill.class);
            if (!CollectionUtils.isEmpty(billList)) {
                //通过服务费账单获取账单维度发票发票明细
                List<String> billIds = billList.stream().map(Bill::getId).collect(Collectors.toList());
                List<InvoiceDetailBill> invoiceDetailBills = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL_BILL).selectField("*")
                        .in("bill_id", billIds)
                        .queryForPOJOList(InvoiceDetailBill.class);
                if (!CollectionUtils.isEmpty(invoiceDetailBills)) {
                    List<String> invoiceApplyIds = invoiceDetailBills.stream().map(InvoiceDetailBill::getId).distinct().collect(Collectors.toList());
                    List<InvoiceApply> invoiceApplyList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField("*")
                            .in("id", invoiceApplyIds)
                            .queryForPOJOList(InvoiceApply.class);
                    invoiceApplyEntityList.addAll(invoiceApplyList);
                }
            }

            if (!CollectionUtils.isEmpty(invoiceApplyEntityList)) {
                List<String> closeIds;
                for (InvoiceApply invoiceApplyEntity : invoiceApplyEntityList) {
                    if (InvoiceStatus.New.name().equals(invoiceApplyEntity.getStatuss())
                            || InvoiceStatus.Returned.name().equals(invoiceApplyEntity.getStatuss())
                            || InvoiceStatus.Approving.name().equals(invoiceApplyEntity.getStatuss())
                            || InvoiceStatus.DrawerConfirming.name().equals(invoiceApplyEntity.getStatuss())) {
                        closeIds = invoiceApplyService.close(Collections.singletonList(invoiceApplyEntity.getId()), InvoiceStatus.settleToClose());
                        if (!CollectionUtils.isEmpty(closeIds)) {
                            result.append("</br>发票编号").append(StringUtils.join(closeIds, ',')).append("已自动关闭。");
                        }
                    } else {
                        result.append("</br>发票编号").append(invoiceApplyEntity.getId()).append("需要手动关闭发票。");
                    }
                }
            }

            if (!CollectionUtils.isEmpty(settleDetailEntityList)) {
                Set<SettleDetail> settleDetailEntitySet = settleDetailEntityList.stream().filter(t -> t.getPlatform().compareTo(BigDecimal.ZERO) > 0 || t.getInterest().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toSet());
                //获取结算明细的账单ID
                List<String> settleDetailIdCollect = settleDetailEntitySet.stream().map(SettleDetail::getId).collect(Collectors.toList());

                //删除对应的服务费账单
                if (!CollectionUtils.isEmpty(settleDetailIdCollect)) {
                    billService.deleteService(settleDetailIdCollect);
                }
            }
        }
    }

    @Override
    public void delete(String settleId) {
        Settle settle = this.loadById(settleId);
        Assert.notNull(settle, "要删除的结算单不存在");
        Assert.isTrue(settle.getStatuss() == SettleStatus.New, "只能新建状态才可删除");
        List<SettleDetail> settleDetailList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                .eq("settle_id", settle.getId())
                .queryForPOJOList(SettleDetail.class);
        if (!CollectionUtils.isEmpty(settleDetailList)) {
            //删除对应明细
            List<String> idCollect = settleDetailList.stream().map(SettleDetail::getId).distinct().collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(idCollect)) {
                deleteDetail(Collections.singletonList(settle), idCollect, true);
            }
        }
        BoServiceUtils.deleteBo(ModelConst.T_SETTLE, settleId, true);
    }

    @Override
    public String close(List<String> settleIds) {
        StringBuffer sBuffer = new StringBuffer();

        log.info("平台采购付款关闭结算单{}",String.join(",", settleIds));

        List<Settle> settleDoneList = new ArrayList<>();
        List<String> settleCloseIds = new ArrayList<>();
        for (String settleId : settleIds) {
            Settle settleEntity = loadById(settleId);
            Assert.notNull(settleEntity, "未查到要关闭的结算单");
            if (settleEntity.getStatuss() != SettleStatus.Returned) {
                JdbcTemplateUtils.builder(ModelConst.T_SETTLE)
                        .putFieldAndVal("statuss", SettleStatus.Returned.name())
                        .eq("id", settleId)
                        .update();

                List<SettleDetail> settleDetailEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                        .in("settle_id", settleId)
                        .queryForPOJOList(SettleDetail.class);
                if (!CollectionUtils.isEmpty(settleDetailEntityList)) {
                    //回写发票可申请结算金额
                    List<String> invoiceIds = settleDetailEntityList.stream().map(SettleDetail::getInvoice_apply_id).distinct().collect(Collectors.toList());
                    invoiceApplyService.writeBackInvoiceWriteOffAmountByInvoiceApply(invoiceIds);

                    //回写交易
                    List<String> tradeIds = settleDetailEntityList.stream().map(SettleDetail::getTrade_id).distinct().collect(Collectors.toList());
                    writeBackTrade(tradeIds);
                }
                sBuffer.append("结算单").append(settleEntity.getId()).append("关闭结算单成功。\n");

                if (settleEntity.getStatuss() == SettleStatus.Done) {
                    settleDoneList.add(settleEntity);
                }
                settleCloseIds.add(settleEntity.getId());
            } else {
                sBuffer.append("结算单").append(settleEntity.getId()).append("已关闭，不能再次关闭\n");
            }

        }
        this.deleteBillServiceAndCloseServiceInvoice(settleCloseIds, sBuffer);

        // 如果已付款，则取消付款删除凭证
        if (settleDoneList.size()>0){
            kingDeeFinanceService.close(settleDoneList);
        }

        return sBuffer.toString();
    }

    @Override
    public void closeByTrade(List<String> tradeIds) {
        Assert.notNull(tradeIds, "关闭结算单参数不能为空");
        List<String> result = new ArrayList<>();

        List<SettleDetail> settleDetailEntityCloseList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                .in("trade_id", tradeIds)
                .queryForPOJOList(SettleDetail.class);
        settleDetailEntityCloseList.stream().collect(Collectors.groupingBy(SettleDetail::getSettle_id))
                .forEach((settleIdKey, settleDetailValue) -> {
                    Settle settleEntity = loadById(settleIdKey);
                    Assert.notNull(settleEntity, "未查到要关闭的结算单");
                    if (SettleStatus.closeStatus().contains(settleEntity.getStatuss())) {
                        JdbcTemplateUtils.builder(ModelConst.T_SETTLE)
                                .putFieldAndVal("statuss", SettleStatus.Returned.name())
                                .eq("id", settleEntity.getId())
                                .update();

                        //更新已核销数据的发票可核销金额
                        if (!CollectionUtils.isEmpty(settleDetailValue)) {
                            //统计关闭的结算明细的发票ID
                            List<String> invoiceIdList = new ArrayList<>();
                            for (SettleDetail settleDetailCloseEntity : settleDetailValue) {
                                invoiceIdList.add(settleDetailCloseEntity.getInvoice_apply_id());
                            }
                            //获取发票对应的有效的结算明细
                            List<SettleDetail> settleDetailEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                                    .in("invoice_apply_id", invoiceIdList)
                                    .queryForPOJOList(SettleDetail.class);

                            //回写发票可核销金额
                            invoiceIdList = settleDetailEntityList.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toList());
                            invoiceApplyService.writeBackInvoiceWriteOffAmountByInvoiceApply(invoiceIdList);

                            //找到被删除明细相同交易的其他没有删除的结算明细
                            Set<String> tradeIdLists = settleDetailEntityList.stream().map(SettleDetail::getTrade_id).collect(Collectors.toSet());
                            //回写交易（其他没有删除的结算明细的交易）
                            writeBackTrade(tradeIdLists);
                        }
                        result.add(settleIdKey);
                    }
                });
        //回写交易（申请关闭的交易）
        writeBackTrade(tradeIds);
    }

    @Override
    public void writeOffSettle(SettleInvoice settleInvoice) {
        Settle settleEntity = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .eq("id", settleInvoice.getId())
                .queryForPOJO(Settle.class);
        Assert.notNull(settleEntity, "要核销的结算单不存在");
        Assert.isTrue(settleEntity.getStatuss() == SettleStatus.Done, "只有已付款完成的结算单才可以核销");

        //过滤掉本次核销金额为null和<=0的
        settleInvoice.getSettleInvoiceDetails().removeIf(item -> item.getBatch_total() == null);
        settleInvoice.getSettleInvoiceDetails().removeIf(item -> item.getBatch_total().doubleValue() <= 0.00);

        List<SettleInvoiceDetail> settleInvoiceDetailList = settleInvoice.getSettleInvoiceDetails();
        Assert.isTrue(!CollectionUtils.isEmpty(settleInvoiceDetailList), "核销明细信息不能为空");

        List<String> invoiceApplyIdList = settleInvoiceDetailList.stream().map(SettleInvoiceDetail::getApply_id).distinct().collect(Collectors.toList());
        //核销的发票数据
        List<InvoiceApply> invoiceApplyList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField("*")
                .eq("statuss", InvoiceStatus.Done.name())
                .in("id", invoiceApplyIdList)
                .queryForPOJOList(InvoiceApply.class);
        Assert.notEmpty(invoiceApplyList, "核销的发票数据不存在");

        //判断发票的销售平台或者采购平台是否唯一
        if (SettleBusinessType.SaleReceivable.name().equals(settleEntity.getBusiness_type())) {
            List<InvoiceApply> saleInvoiceList = invoiceApplyList.stream().filter(item -> item.getSale_organization_id().getId().equals(settleEntity.getSale_organization_id().getId()))
                    .collect(Collectors.toList());
            Assert.isTrue(saleInvoiceList.size() == invoiceApplyList.size(), "核销发票的平台销售组织不唯一");
        } else {
            List<InvoiceApply> purchaseInvoiceList = invoiceApplyList.stream().filter(item -> item.getPurchase_organization_id().getId().equals(settleEntity.getPurchase_organization_id().getId()))
                    .collect(Collectors.toList());
            Assert.isTrue(purchaseInvoiceList.size() == invoiceApplyList.size(), "核销发票的平台采购组织不唯一");
        }

        //判断发票的业务类型是否都为货物发票或者服务费发票
        List<InvoiceBusinessType> invoiceBusinessTypeList = invoiceApplyList.stream()
                .map(t -> InvoiceBusinessType.valueOf(t.getBusiness_type())).distinct().collect(Collectors.toList());
        Assert.isTrue(invoiceBusinessTypeList.size() == 1, "核销的发票业务类型不唯一");

        //代购和非代购的发票不能一起核销
        List<TradeOrderType> tradeOrderTypes = invoiceApplyList.stream().map(t -> Enum.valueOf(TradeOrderType.class, t.getTrade_order_type())).collect(Collectors.toList());
        Assert.isTrue(tradeOrderTypes.size() == 1, "代购发票和非代购发票不能一起核销");
        Assert.isTrue((settleEntity.isContract() && tradeOrderTypes.get(0) == TradeOrderType.Agent)
                || (!settleEntity.isContract() && tradeOrderTypes.get(0) == TradeOrderType.Ordinary), "代购和非代购不能进行核销");

        //根据申请ID和ID类型获取可结算数据
        SettleApplyQuery settleApplyQuery = SettleApplyQuery.builder()
                .apply_type(settleInvoice.getApply_type())
                .ids(settleInvoice.getDetailApplyIds()).build();
        SettleInvoice canSettleInvoice = this.getCanApply(settleApplyQuery);
        Assert.notNull(canSettleInvoice, "未获取可结算发票数据");

        //构建结算单明细
        List<SettleDetail> settleDetailList = this.buildSettleDetail(canSettleInvoice, settleInvoiceDetailList);
        settleDetailList.removeIf(t -> t.getTotal().compareTo(BigDecimal.ZERO) == 0);



        BigDecimal interestSum = BigDecimal.ZERO;
        BigDecimal platformSum = BigDecimal.ZERO;
        //采购付款结算单 或者 销售收款的代购 需要重新计算平台费和垫资服务费
        if (SettleBusinessType.PurchasePayment.name().equals(settleEntity.getBusiness_type())) {
            //明细对应账单
            List<Bill> billList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField(" * ")
                    .eq("id", settleDetailList.stream().map(SettleDetail::getBill_id).collect(Collectors.toList()))
                    .queryForPOJOList(Bill.class);
            //明细对应交易
            List<Trade> tradeList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                    .eq("id", settleDetailList.stream().map(SettleDetail::getTrade_id).collect(Collectors.toList()))
                    .queryForPOJOList(Trade.class);
            for (SettleDetail settleDetail : settleDetailList) {
                Trade trade = tradeList.stream().filter(t -> t.getId().equals(settleDetail.getTrade_id())).findFirst().get();
                Bill bill = billList.stream().filter(t -> t.getId().equals(settleDetail.getBill_id())).findAny().get();
                //供应商对应客户是否回款
                boolean repayment = tradeService.isRepayment(trade.getOrder_goods_id(), trade.getDirection());
                //平台利率，有自定义利率按自定义算，没有则按交易记录的平台利率
                BigDecimal platformRate = settleEntity.getPlatform_rate() == null ? trade.getPlatform_rate() : BigDecimalUtils.div(settleEntity.getPlatform_rate(),100);
                //计算平台费
                Map<String, BigDecimal> platformFeeMap = this.calculationPlatform(platformRate, settleDetail.getTotal());
                //计算垫资费
                Date inquiryTime = DateUtils.strToDate(trade.getExtends_attr().getInquiryTime());
                Map<String, BigDecimal> interestFeeMap = this.calculationPurchasePaymentInterest(bill.getBill_date(), trade.getAccount_period().intValue(),
                        settleDetail.getTotal(), repayment, inquiryTime, settleEntity.getInterest_rate(), settleEntity.getApply_time());
                settleDetail.setInterest(interestFeeMap.get("interestFee")).setInterest_rate(interestFeeMap.get("interestRate"));
                settleDetail.setPlatform(platformFeeMap.get("platformFee")).setPlatform_rate(platformFeeMap.get("platformRate"));
                interestSum = interestSum.add(settleDetail.getInterest());
                platformSum = platformSum.add(settleDetail.getPlatform());
            }
        }
        //代购生成代购服务费
        else if(settleEntity.isContract() && SettleBusinessType.SaleReceivable.name().equals(settleEntity.getBusiness_type())){
            //计算代购服务费并生成
            buildContractServiceFee(settleDetailList);
        }
        BigDecimal total = BigDecimal.ZERO;
        for (SettleDetail settleDetail : settleDetailList) {
            settleDetail.setSettle_id(settleEntity.getId());
            BigDecimal service = settleDetail.getInterest().add(settleDetail.getPlatform());
            if (settleEntity.isContract()) {
                service = BigDecimal.ZERO;
            }
            total = total.add(settleDetail.getTotal().subtract(service));
        }
        //对本次申请核销金额和结算单可核销金额做校验
        Assert.isTrue(settleEntity.getWrite_off_total().compareTo(total)>=0, "本次核销金额不能大于结算单可核销金额");

        List<Map<String, Object>> mapList = settleDetailList.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());
        BoServiceUtils.createBo(ModelConst.T_SETTLE_DETAIL, mapList);
        //更新结算单可核销金额
        settleEntity.setWrite_off_total(getSettleWriteOffAmount(settleEntity.getId()));
        settleEntity.setWoffNow(settleEntity.getWrite_off_total().compareTo(BigDecimal.ZERO) > 0 ? "0" : "1");

        Assert.isTrue(settleEntity.getWrite_off_total().doubleValue() >= 0, "本次申请核销金额：" + total
                + "大于可核销金额" + settleEntity.getWrite_off_total());

        //更新发票号码，确认人
        List<String> invoiceIdList = settleDetailList.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toList());
        settleEntity.setInvoice_number(this.getSettleInvoiceNumber(settleEntity.getId()))
                .setConfirm_member_id(RequestContext.getCorpLoginId())
                .setConfirm_member_name(RequestContext.getLoginRealName())
                //获取发票的发票抬头，更新到收款单的抬头
                .setPurchase_name(getSettlePurchaseName(invoiceIdList, settleEntity));
        //代购生成服务费账单
        if (settleEntity.isContract()) {
            List<String> invoiceServiceIds = this.generateServiceFeeBill(settleEntity.getId());
            settleEntity.setInvoice_service_ids(String.join(",", invoiceServiceIds));
        }
        BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, settleEntity.beanToMap());

        //回写发票可核销金额和已核销金额
        List<SettleDetail> settleDetailsAll = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField(" * ")
                .eq("settle_id", settleEntity.getId())
                .queryForPOJOList(SettleDetail.class);
        invoiceApplyService.writeBackInvoiceWriteOffAmountByInvoiceApply(settleDetailsAll.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toList()));
        //回写交易
        this.writeBackTrade(settleDetailsAll.stream().map(SettleDetail::getTrade_id).collect(Collectors.toList()));

        //核销的不是代购服务费发票，则需要生成凭证和扣除信用
        if (invoiceBusinessTypeList.get(0) != InvoiceBusinessType.Service && invoiceBusinessTypeList.get(0) != InvoiceBusinessType.RedService) {

            //整理数据，明细中赋值发票抬头和发票号码
            settleInvoiceDetailList.stream().collect(Collectors.groupingBy(SettleInvoiceDetail::getApply_id))
                    .forEach((invoiceApplyIdKey, settleInvoiceDetailValue) -> {
                        InvoiceApply invoiceApplyEntity = invoiceApplyService.loadById(invoiceApplyIdKey);
                        for (SettleInvoiceDetail settleInvoiceDetail : settleInvoiceDetailValue) {
                            settleInvoiceDetail.setInvoice_purchase_name(invoiceApplyEntity.getPurchase_name());
                            settleInvoiceDetail.setNumber(invoiceApplyEntity.getNumber());
                        }
                    });
            // 凭证部分，total和settleInvoiceDetailList需要赋值最新的
            settleEntity.setTotal(total);
            settleEntity.setSettleInvoiceDetailList(settleInvoiceDetailList);
            kingDeeFinanceService.writeOffSettleByInvoice(settleEntity);

            //更新信用额度
            organizationAccountService.saveByPayment(Collections.singletonList(settleEntity.getId()), 1);
        }

    }

    /**
     * 销售代购收款，代购服务费生成
     *
     * @param settleDetailEntityList
     */
    public void buildContractServiceFee(List<SettleDetail> settleDetailEntityList) {
        List<String> tradeIds = settleDetailEntityList.stream().map(SettleDetail::getId).collect(Collectors.toList());
        List<Trade> trades = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                .in("id", tradeIds)
                .queryForPOJOList(Trade.class);
        //待核销订单商品ID和金额
        List<ContractWriteOffRecord> prepareWriteOffParam = new ArrayList<>();
        for (SettleDetail settleDetail : settleDetailEntityList) {
            List<Trade> mappingTrades = trades.stream().filter(t -> t.getId().equals(settleDetail.getTrade_id())).collect(Collectors.toList());
            Assert.isTrue(!mappingTrades.isEmpty(), "从交易获取服务费费率异常");
            prepareWriteOffParam.add(ContractWriteOffRecord.builder()
                    .write_off_amount(settleDetail.getTotal())
                    .order_customer_goods_id(mappingTrades.get(0).getOrder_goods_id())
                    .build());

        }
        //根据云平台订单商品ID获取会员采购订单id
        List<String> orderGoodIds = trades.stream().map(Trade::getOrder_goods_id).collect(Collectors.toList());
        String sql = "select orderGood.cloud_order_goods_id, memberGood.member_purchase_order_id from " + AppConst.ORDER_CENTER + "." + JdbcTemplateUtils.getTableName(ModelConst.T_MEMBER_PURCHASE_ORDER_GOODS) + " as memberGood" +
                " left join " + AppConst.ORDER_CENTER + "." + JdbcTemplateUtils.getTableName(ModelConst.T_TRANSFER_ORDER_GOODS) + " as orderGood" +
                " on memberGood.transfer_order_goods_id = orderGood.id " +
                " left join " + AppConst.ORDER_CENTER + "." + JdbcTemplateUtils.getTableName(ModelConst.T_MEMBER_PURCHASE_ORDER) + " as memberOrder" +
                " on memberOrder.id = memberGood.member_purchase_order_id" +
                " where orderGood.cloud_order_goods_id in (:orderGoodsId) and memberOrder.is_rp = false and memberOrder.member_purchase_order_status in (3,4)";
        Map<String, Object> param = MapBuilder.create(new HashMap<String, Object>()).put("orderGoodsId", orderGoodIds).build();
        List<Map<String, Object>> memberPurchaseOrderIds = JdbcTemplateUtils.queryForList(sql, param);

        //根据会员采购订单ID，获取采购付款明细列表id，payment_id，member_purchase_order_id
        List<String> memberPurchaseOrderIdList = memberPurchaseOrderIds.stream().map(t -> t.get("member_purchase_order_id").toString()).collect(Collectors.toList());
        String sql2 = "select detail.* from t_purchase_payment_detail detail where detail.deleted = 0 and detai.member_purchase_order_id in (:member_purchase_order_id)" +
                " detail.payment_detail_status = 3 order by detail.financial_confirm_time";
        param.clear();
        param.put("member_purchase_order_id", memberPurchaseOrderIdList);
        List<Map<String, Object>> purchasePaymentDetailList = JdbcTemplateUtils.queryForList(sql2, param);

        //根据转采付款明细ID获取代购转采已核销记录
        List<String> paymentDetailIds = purchasePaymentDetailList.stream().map(t -> t.get("id").toString()).collect(Collectors.toList());
        List<ContractWriteOffRecord> alreadyContractWriteOffRecords = JdbcTemplateUtils.builder(ModelConst.T_CONTRACT_WRITE_OFF_RECORD).selectField("*")
                .in("transfer_payment_detail_id", paymentDetailIds)
                .queryForPOJOList(ContractWriteOffRecord.class);
        //根据代购转已采核销记录对付款记录排序，已有核销记录的靠前
        purchasePaymentDetailList = this.sortByContractRecord(purchasePaymentDetailList, alreadyContractWriteOffRecords);
        //根据代购转采订单付款明细前后顺序排序
        memberPurchaseOrderIds = sortByPaymentDetail(memberPurchaseOrderIds, purchasePaymentDetailList);
        List<ContractWriteOffRecord> contractWriteOffRecords = this.buildContractWriteOffRecord(prepareWriteOffParam, memberPurchaseOrderIds, purchasePaymentDetailList, alreadyContractWriteOffRecords);

        for (SettleDetail settleDetail : settleDetailEntityList) {
            Trade trade = trades.stream().filter(t -> settleDetail.getTrade_id().equals(t.getId())).distinct().collect(Collectors.toList()).get(0);
            List<ContractWriteOffRecord> mappingContractWriteOffRecords = contractWriteOffRecords.stream().filter(t -> t.getWrite_off_amount().equals(settleDetail.getTotal())).distinct().collect(Collectors.toList());
            //转采金额需要大于等于核销金额
            BigDecimal sumContractWriteOff = CalculatorUtils.sum(mappingContractWriteOffRecords, BiFunctionConst.contractWriteOffRecordTotalFun);
            Assert.isTrue(sumContractWriteOff.compareTo(settleDetail.getTotal()) >= 0,
                    "交易编号" + settleDetail.getTrade_id() + "的核销金额" + settleDetail.getTotal() + "必须等于转采金额" + sumContractWriteOff);

            List<String> settleIds = settleDetailEntityList.stream().map(SettleDetail::getSettle_id).distinct().collect(Collectors.toList());
            Assert.isTrue(!CollectionUtils.isEmpty(settleIds) && settleIds.size() == 1, "结算明细获取的结算单数量异常" + settleIds.size());
            Settle settle = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                    .eq("id", settleIds.get(0))
                    .queryForPOJO(Settle.class);
            Assert.notNull(settle, "未获取到对应结算单");

            //平台销售收款时间取确认付款时间
            Date saleReceivableDate = settle.getConfirm_time();

            BigDecimal contractServiceFee = BigDecimal.ZERO;
            for (ContractWriteOffRecord contractWriteOffRecord : contractWriteOffRecords) {
                //销售收款日期-转采付款日期的天数差，最少为0，不能为负数
                long time = saleReceivableDate.getTime() / 1000 - contractWriteOffRecord.getTransfer_payment_time().getTime() / 1000;
                int day = (int) (time / (3600 * 24));

                //调用转采服务费计算方法，计算垫资服务费费s
                BigDecimal contractService = contractServiceFeeTemplateService.getContractServiceFee(trade.getOrganization_id().getId(), contractWriteOffRecord.getWrite_off_amount(), day);
                contractServiceFee = BigDecimalUtils.round(BigDecimalUtils.add(contractServiceFee, contractService), 2);
                BoServiceUtils.createBo(ModelConst.T_CONTRACT_WRITE_OFF_RECORD, Collections.singletonList(BeanUtil.beanToMap(contractWriteOffRecord)));
            }
            BigDecimal contractInterestRate = BigDecimalUtils.round(BigDecimalUtils.div(contractServiceFee, settleDetail.getTotal()), 2);
            settleDetail.setInterest(contractServiceFee).setInterest_rate(contractInterestRate);
        }

    }

    /**
     * 根据代购转已采核销记录对付款记录排序
     * 已有核销记录的靠前
     *
     * @param filterPaymentDetailList    代购转采订单付款明细
     * @param contractWriteOffRecordList 代购转采付款核销记录
     * @return
     */
    private List<Map<String, Object>> sortByContractRecord(List<Map<String, Object>> filterPaymentDetailList,
                                                           List<ContractWriteOffRecord> contractWriteOffRecordList) {
        if (CollectionUtils.isEmpty(contractWriteOffRecordList)) {
            return filterPaymentDetailList;
        }

        List<Map<String, Object>> results = new ArrayList<>();
        for (ContractWriteOffRecord record : contractWriteOffRecordList) {
            if (results.stream().anyMatch(t -> t.get("id").toString().equals(record.getTransfer_payment_detail_id()))) {
                continue;
            }

            filterPaymentDetailList
                    .stream().filter(t -> t.get("id").toString().equals(record.getTransfer_payment_detail_id())).findFirst().ifPresent(results::add);
        }

        for (Map<String, Object> paymentDetail : filterPaymentDetailList) {
            if (results.stream().anyMatch(t -> t.get("id").equals(paymentDetail.get("id")))) {
                continue;
            }
            results.add(paymentDetail);
        }

        return results;
    }

    private List<Map<String, Object>> sortByPaymentDetail(List<Map<String, Object>> purchaseOrderGoodsList, List<Map<String, Object>> paymentDetailList) {
        List<Map<String, Object>> results = new ArrayList<>();
        for (Map<String, Object> paymentDetail : paymentDetailList) {
            if (results.stream().anyMatch(t -> t.get("member_purchase_order_id").toString().equals(paymentDetail.get("member_purchase_order_id").toString()))) {
                continue;
            }

            results.addAll(purchaseOrderGoodsList.stream()
                    .filter(t -> t.get("member_purchase_order_id").toString().equals(paymentDetail.get("member_purchase_order_id").toString())).collect(Collectors.toList()));
        }

        return results;
    }

    /**
     * 构建代购转采核销记录
     *
     * @param params                     订单商品ID和对应的交易金额
     * @param purchaseOrderGoodsList     采购订单商品
     * @param paymentDetailList          代购转采订单付款明细
     * @param contractWriteOffRecordList 已核销的代购转采订单付款明细记录
     * @return 可生成的代购转采付款明细核销记录
     */
    private List<ContractWriteOffRecord> buildContractWriteOffRecord(List<ContractWriteOffRecord> params,
                                                                     List<Map<String, Object>> purchaseOrderGoodsList,
                                                                     List<Map<String, Object>> paymentDetailList,
                                                                     List<ContractWriteOffRecord> contractWriteOffRecordList) {
        List<ContractWriteOffRecord> results = new ArrayList<>();
        for (ContractWriteOffRecord param : params) {
            //根据平台订单商品ID获取转采订单ID并根据转采订单ID获取转采付款明细列表，目的是为了获取平台订单商品对应的转采付款明细列表
            List<Map<String, Object>> filterPurchaseOrderGoodsList = purchaseOrderGoodsList.stream()
                    .filter(t -> t.get("cloud_order_goods_id").equals(param.getOrder_customer_goods_id())).collect(Collectors.toList());
            List<String> memberPurchaseOrderIds = filterPurchaseOrderGoodsList.stream().map(t -> t.get("member_purchase_order_id").toString()).collect(Collectors.toList());

            List<Map<String, Object>> filterPaymentDetailList = paymentDetailList
                    .stream().filter(t -> memberPurchaseOrderIds.contains(t.get("member_purchase_order_id").toString())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filterPaymentDetailList)) {
                continue;
            }

            BigDecimal currentWriteOffAmount = param.getWrite_off_amount();
            for (Map<String, Object> paymentDetail : filterPaymentDetailList) {
                if (currentWriteOffAmount.compareTo(BigDecimal.ZERO) < 1) {
                    break;
                }

                //减去已核销的金额
                List<ContractWriteOffRecord> filterContractWriteOffRecordList = contractWriteOffRecordList
                        .stream().filter(t -> t.getTransfer_payment_detail_id().equals(paymentDetail.get("id").toString())).collect(Collectors.toList());
                BigDecimal writeOffAmount = BigDecimal.ZERO;
                for (ContractWriteOffRecord record : filterContractWriteOffRecordList) {
                    writeOffAmount = BigDecimalUtils.add(record.getWrite_off_amount(), writeOffAmount);
                }

                writeOffAmount = BigDecimalUtils.sub(new BigDecimal(paymentDetail.get("payment").toString()), writeOffAmount);
                if (writeOffAmount.compareTo(BigDecimal.ZERO) == 1) {

                    BigDecimal tempCurrentWriteOffAmount = currentWriteOffAmount;
                    currentWriteOffAmount = BigDecimalUtils.sub(currentWriteOffAmount, writeOffAmount);

                    ContractWriteOffRecord record = ContractWriteOffRecord.builder()
                            .transfer_payment_detail_id(paymentDetail.get("id").toString())
                            .order_customer_goods_id(filterPurchaseOrderGoodsList.get(0).get("cloud_order_goods_id").toString())
                            .write_off_amount(currentWriteOffAmount.compareTo(BigDecimal.ZERO) < 1 ? tempCurrentWriteOffAmount : writeOffAmount)
                            .transfer_payment_time((Date) paymentDetail.get("financial_confirm_time"))
                            .build();

                    results.add(record);
                }
            }
        }

        return results;
    }


    @Override
    public void writeOffSettleCancel(WriteOffCancelIds cancelIds) {
        JdbcTemplateUtils jdbcTemplateUtils = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*");
        if (!CollectionUtils.isEmpty(cancelIds.getInvoiceIds())) {
            jdbcTemplateUtils.in("invoice_apply_id", cancelIds.getInvoiceIds());
        }
        if (!CollectionUtils.isEmpty(cancelIds.getSettleIds())) {
            jdbcTemplateUtils.in("settle_id", cancelIds.getSettleIds());
        }
        List<SettleDetail> settleDetailList = jdbcTemplateUtils.queryForPOJOList(SettleDetail.class);
        Assert.notEmpty(settleDetailList, "不存在可取消核销的结算单明细");
        List<Settle> settleList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .in("id", settleDetailList.stream().map(SettleDetail::getSettle_id).collect(Collectors.toList()))
                .queryForPOJOList(Settle.class);
        List<Settle> notDoneList = settleList.stream().filter(t -> t.getStatuss() != SettleStatus.Done).collect(Collectors.toList());
        Assert.isTrue(notDoneList.size() == 0, "已付款状态才能取消核销");

        this.deleteDetail(settleList, settleDetailList.stream().map(SettleDetail::getId).collect(Collectors.toList()), false);
        for (Settle settle : settleList) {
            //更新结算单的可核销金额、发票号码
            BigDecimal writoOffTotal = getSettleWriteOffAmount(settle.getId());
            JdbcTemplateUtils.builder(ModelConst.T_SETTLE)
                    .putFieldAndVal("write_off_total", writoOffTotal)
                    .putFieldAndVal("woffNow", writoOffTotal.compareTo(BigDecimal.ZERO) > 0 ? true : false)
                    .putFieldAndVal("invoice_number", getSettleInvoiceNumber(settle.getId()))
                    .eq("id", settle.getId())
                    .update();
            //删除核销凭证
            kingDeeFinanceService.writeOffCancel(settle.getId());
        }
    }

    /**
     * 获取结算单核销明细的发票号码
     *
     * @param settleId
     * @return 以“,”隔开的发票号码
     */
    private String getSettleInvoiceNumber(String settleId) {
        List<SettleDetail> settleDetailList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField(" invoice_apply_id ")
                .in("settle_id", settleId)
                .queryForPOJOList(SettleDetail.class);
        if (settleDetailList.size() == 0) {
            return "";
        }
        List<InvoiceApply> invoiceApplyList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField(" number ")
                .in("id", settleDetailList.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toSet()))
                .queryForPOJOList(InvoiceApply.class);
        return String.join(",", invoiceApplyList.stream().map(InvoiceApply::getNumber).collect(Collectors.toList()));
    }

    /**
     * 获取结算单对应发票的抬头，新的发票抬头排在前面
     *
     * @param invoiceIdList 新核销的发票id
     * @param settle        结算单
     * @return
     */
    private String getSettlePurchaseName(List<String> invoiceIdList, Settle settle) {
        List<InvoiceApply> invoiceApplyList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField(" purchase_name ")
                .in("id", invoiceIdList)
                .queryForPOJOList(InvoiceApply.class);
        Set<String> result = new LinkedHashSet<>();
        List<String> purchaseNameOldList = Arrays.asList(settle.getPurchase_name().split(";"));
        if (invoiceApplyList.size() > 0) {
            Set<String> pruchaseNameNewList = invoiceApplyList.stream().map(InvoiceApply::getPurchase_name).collect(Collectors.toSet());
            for (String purchaseName : pruchaseNameNewList) {
                if (!purchaseNameOldList.contains(purchaseName)) {
                    result.add(purchaseName);
                }
            }
        }
        result.addAll(purchaseNameOldList);
        return String.join(",", result);
    }

    /**
     * 删除结算单明细
     * 回写交易的可结算金额，回写发票的可核销金额和已核销金额
     *
     * @param settleDetailIds
     * @param verifyStatus    是否根据结算单状态删除 verifyStatus=true 只有新建状态才可以删除
     */
    private void deleteDetail(List<Settle> settleList, List<String> settleDetailIds, boolean verifyStatus) {
        log.info("删除结算明细并且回写发票可核销金额、回写交易");
        List<SettleDetail> settleDetailList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                .in("id", settleDetailIds)
                .queryForPOJOList(SettleDetail.class);
        if (!CollectionUtils.isEmpty(settleDetailList)) {
            Assert.isTrue(settleDetailIds.size() == settleDetailList.size(), "期望删除的和实际要删除的明细不等");
            //标记删除
            for (SettleDetail settleDetailEntity : settleDetailList) {
                if (verifyStatus) {
                    Settle settle = settleList.stream().filter(t -> t.getId().equals(settleDetailEntity.getSettle_id())).findAny().get();
                    Assert.notNull(settle, "删除结算明细时，未获取到对应结算单信息");
                    Assert.isTrue(SettleStatus.New.equals(settle.getStatuss()), "只能新建状态才可删除");
                }
                BoServiceUtils.deleteBo(ModelConst.T_SETTLE_DETAIL, settleDetailEntity.getId(), true);
            }

            //回写发票的可核销金额
            List<String> invoiceApplyIds = settleDetailList.stream().map(SettleDetail::getInvoice_apply_id).distinct().collect(Collectors.toList());
            invoiceApplyService.writeBackInvoiceWriteOffAmountByInvoiceApply(invoiceApplyIds);

            //找到被删除明细相同交易的其他没有删除的结算明细
            List<String> tradeIds = settleDetailList.stream().map(SettleDetail::getTrade_id).distinct().collect(Collectors.toList());

            //回写交易
            writeBackTrade(tradeIds);
        }
    }

    /**
     * 发票是否已经申请结算
     *
     * @param invoiceIdList 发票ID列表
     * @return false 未申请，true 已申请
     */
    @Override
    public boolean isInvoiceHaveSettled(List<String> invoiceIdList) {
        List<SettleStatus> settleStatusList = new ArrayList<>(Arrays.asList(SettleStatus.New, SettleStatus.Confirming,
                SettleStatus.ApprovingBusiness, SettleStatus.ApprovingFinance, SettleStatus.Approving,
                SettleStatus.PartDone, SettleStatus.Done));

        StringBuffer sql = new StringBuffer("select detail.*, statuss from " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE_DETAIL) + " detail");
        sql.append(" inner join " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE) + " settle");
        sql.append(" on settle.id = detail.settle_id and settle.deleted = 0 ");
        sql.append(" where detail.invoice_apply_id in (:invoiceApplyIds)");
        sql.append(" and settle.statuss in (:statuss)");
        Map<String, Object> param = MapBuilder.create(new HashMap<String, Object>())
                .put("invoiceApplyIds", invoiceIdList)
                .put("statuss", settleStatusList)
                .build();
        List<Map<String, Object>> list = JdbcTemplateUtils.queryForList(sql.toString(), param);
        return list.size() > 0;

    }

    /**
     * 回写交易的结算状态，可结算金额，客户回款状态
     * 调用点：
     * 1、销售收款核销发票
     * 2、平台采购付款提交
     * 3、平台采购确认付款
     * 4、平台采购付款关闭结算单
     * 5、据交易ID关闭结算单
     * 6、删除结算明细
     * 7、取消核销（删除结算明细）
     *
     * @param tradeIds 交易Id列表
     */
    public void writeBackTrade(Collection<String> tradeIds) {
        log.info(">>>>>>>>>开始>>>>>>>回写交易的结算状态，可结算金额，客户回款状态");

        //根据交易获取所有结算明细
        String sql = " select detail.* from " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE_DETAIL) + " as detail" +
                " left join " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE) + " as settle on settle.id = detail.settle_id" +
                " where settle.deleted = 0 and detail.deleted = 0" +
                "  and detail.trade_id in (:tradeId) and settle.statuss in (:status)";
        Map<String, Object> param = new HashMap<>();
        param.put("tradeId", tradeIds);
        param.put("status", SettleStatus.normalStatus());
        List<SettleDetail> settleDetailEntityList = JdbcTemplateUtils.queryForPOJOList(sql, param, ModelConst.T_SETTLE_DETAIL, SettleDetail.class);

        //全部交易都没有结算
        if (CollectionUtils.isEmpty(settleDetailEntityList)) {
            List<Trade> tradeList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                    .in("id", tradeIds)
                    .queryForPOJOList(Trade.class);
            for (Trade tradeEntity : tradeList) {
                //退货账单金额
                List<Bill> billRefundEntityList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                        .eq("type", BillType.Refund.name()).in("trade_id", tradeIds)
                        .queryForPOJOList(Bill.class);

                BigDecimal sumBillRefund = CalculatorUtils.sum(billRefundEntityList, BiFunctionConst.billTotalFun);

                //此笔交易付款状态为未付款
                MapBuilder<String, Object> map = MapBuilder.create(new HashMap<String, Object>())
                        .put("id", tradeEntity.getId())
                        .put("allowed_settle_amount", BigDecimalUtils.sub(tradeEntity.getAmount(), sumBillRefund))
                        .put("settle_status", TradeSettleStatus.Undo.name())
                        .put("payment_type", TradeSettleStatus.Undo.name());//未付款，所以将支付类型设置成Undo

                BoServiceUtils.updateMainBo(ModelConst.T_TRADE, map.build());
            }
        } else {
            settleDetailEntityList.stream().collect(Collectors.groupingBy(SettleDetail::getTrade_id)).forEach(
                    (tradeIdKey, settleDetailEntityValue) -> {
                        Trade tradeEntity = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                                .eq("id", tradeIdKey).queryForPOJO(Trade.class);

                        List<Bill> billRefundEntityList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                                .eq("trade_id", tradeIdKey)
                                .eq("type", BillType.Refund.name())
                                .queryForPOJOList(Bill.class);
                        //退货账单金额
                        BigDecimal sumBillRefund = CalculatorUtils.sum(billRefundEntityList, BiFunctionConst.billTotalFun);

                        if (CollectionUtils.isEmpty(settleDetailEntityValue)) {
                            MapBuilder<String, Object> map = MapBuilder.create(new HashMap<String, Object>())
                                    .put("id", tradeEntity.getId())
                                    .put("allowed_settle_amount", BigDecimalUtils.sub(tradeEntity.getAmount(), sumBillRefund))
                                    .put("settle_status", TradeSettleStatus.Undo.name())
                                    .put("payment_type", TradeSettleStatus.Undo.name());//未付款，所以将支付类型设置成Undo

                            BoServiceUtils.updateMainBo(ModelConst.T_TRADE, map.build());
                        } else {
                            //交易已核销的金额
                            BigDecimal settleDetailTotal = CalculatorUtils.sum(settleDetailEntityValue, BiFunctionConst.settleDetailTotalFun);

                            //获取结算所有账单，并过滤增补
                            BigDecimal billBanlanceSum = BigDecimal.ZERO;
                            List<String> billIdList = settleDetailEntityValue.stream().map(SettleDetail::getBill_id).distinct().collect(Collectors.toList());
                            List<Bill> billEntityList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                                    .in("id", billIdList)
                                    .queryForPOJOList(Bill.class);
                            if (!CollectionUtils.isEmpty(billEntityList)) {
                                List<Bill> billBanlanceEntityList = billEntityList.stream().filter(t -> t.getType().equals(BillType.Balance.name())).collect(Collectors.toList());
                                billBanlanceSum = CalculatorUtils.sum(billBanlanceEntityList, BiFunctionConst.billTotalFun);
                            }
                            //交易已核销的金额-补差（因为交易金额不包括增补，所有要把结算时增补的账单金额排除）
                            settleDetailTotal = BigDecimalUtils.sub(settleDetailTotal, billBanlanceSum);

                            //可核销金额=交易金额-交易退款金额-已核销金额。可能为负数，退款金额是订单走完退货流程就回写的，如果没有重新核销，计算出来的就是负数
                            BigDecimal allowedSettleAmount = BigDecimalUtils.sub(BigDecimalUtils.sub(tradeEntity.getAmount(), sumBillRefund), settleDetailTotal);

                            //获取结算明细对应结算单的状态
                            Set<SettleStatus> settleStatuses = new HashSet<>();
                            Set<String> settleTypes = new HashSet<>();
                            List<String> settleIds = new ArrayList<>();
                            settleDetailEntityValue.stream().collect(Collectors.groupingBy(SettleDetail::getSettle_id)).forEach(
                                    (settleIdKey, settleDetailInnerEntityValue) -> {
                                        Settle settleEntity = this.loadById(settleIdKey);
                                        settleStatuses.add(settleEntity.getStatuss());
                                        settleTypes.add(settleEntity.getType());
                                        settleIds.add(settleIdKey);
                                    });

                            String settleTypesString = StringUtils.join(settleTypes, ",");

                            //回写交易
                            Map<String, Object> map = MapBuilder.create(new HashMap<String, Object>())
                                    .put("settle_ids", String.join(",", settleIds))
                                    .put("allowed_settle_amount", allowedSettleAmount)
                                    .put("payment_type", settleTypesString).build();
                            if ((settleStatuses.size() == 1 && settleStatuses.iterator().next().equals(SettleStatus.Done)) && allowedSettleAmount.compareTo(BigDecimal.ZERO) == 0) {
                                map.put("settle_status", TradeSettleStatus.Done.name());
                            } else if (settleStatuses.stream().filter(t -> t == SettleStatus.New || t == SettleStatus.Returned).collect(Collectors.toSet()).size() == settleStatuses.size()
                                    || BigDecimalUtils.sub(tradeEntity.getAmount(), allowedSettleAmount).compareTo(BigDecimal.ZERO) == 0) {
                                //未付款
                                map.put("settle_status", TradeSettleStatus.Undo.name());
                            } else {
                                //付款中
                                map.put("settle_status", TradeSettleStatus.Doing.name());
                            }
                            //更新交易的结算状态，付款类型，已结算金额
                            JdbcTemplateUtils.builder(ModelConst.T_TRADE)
                                    .putFieldAndVal(map)
                                    .eq("id", tradeEntity.getId())
                                    .update();
                        }
                    }
            );
        }
        log.info(">>>>>>>>>结束>>>>>>>回写交易的结算状态，可结算金额，客户回款状态");
    }


    @Override
    public SettleInvoice viewSettleInvoice(SettleApplyQuery applyQuery) {
        SettleInvoice viewSettleInvoice = this.getCanApply(applyQuery);
        if (null == viewSettleInvoice) {
            return null;
        }
        List<SettleInvoiceDetail> viewSettleInvoiceDetails = new ArrayList<>();

        List<SettleInvoiceDetail> settleInvoiceDetails = viewSettleInvoice.getSettleInvoiceDetails();
        List<Bill> bills = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                .in("id", settleInvoiceDetails.stream().map(SettleInvoiceDetail::getBill_id).collect(Collectors.toSet()))
                .queryForPOJOList(Bill.class);

        //如果是采购结算，需要计算服务费发票,获取采购发票信息
        Set<TradeDirection> directions = bills.stream().map(t -> Enum.valueOf(TradeDirection.class, t.getDirection())).collect(Collectors.toSet());
        if (TradeDirection.Purchase == directions.iterator().next()) {
            //计算平台费和垫资费
            this.getCanApplyServiceFee(settleInvoiceDetails, bills, applyQuery.getInterest_rate(), applyQuery.getPlatform_rate(), null);

            Set<String> invoiceIds = new HashSet<>();
            if (applyQuery.getApply_type() == SettleApplyType.Invoice) {
                invoiceIds = new HashSet<>(applyQuery.getIds());

            } else if (applyQuery.getApply_type() == SettleApplyType.VENDOR_ORDER) {
                //订单->交易->发票明细
                List<Trade> tradeEntityList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                        .in("vendor_order_id", applyQuery.getIds())
                        .eq("direction", TradeDirection.Purchase.name())
                        .queryForPOJOList(Trade.class);
                Set<String> tradeIds = tradeEntityList.stream().map(Trade::getId).collect(Collectors.toSet());
                List<InvoiceDetailBill> invoiceDetailBillEntityList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL_BILL).selectField("*")
                        .in("trade_id", tradeIds)
                        .queryForPOJOList(InvoiceDetailBill.class);
                invoiceIds = invoiceDetailBillEntityList.stream().map(InvoiceDetailBill::getInvoice_apply_id).collect(Collectors.toSet());

            } else if (applyQuery.getApply_type() == SettleApplyType.Trade) {
                List<InvoiceDetailBill> invoiceDetailBillEntityList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL_BILL).selectField("*")
                        .in("trade_id", applyQuery.getIds())
                        .queryForPOJOList(InvoiceDetailBill.class);
                invoiceIds = invoiceDetailBillEntityList.stream().map(InvoiceDetailBill::getInvoice_apply_id).collect(Collectors.toSet());
            }
            InvoiceApply invoiceApply = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField("*")
                    .in("id", invoiceIds)
                    .queryForPOJOList(InvoiceApply.class).get(0);
            //服务费发票信息
            InvoiceApplyForm invoiceServiceApplyProcess = InvoiceApplyForm.builder()
                    .type(invoiceApply.getType())
                    .purchase_organization_id(invoiceApply.getSale_organization_id())
                    .purchase_organization_name(invoiceApply.getSale_organization_name())
                    .sale_organization_id(invoiceApply.getPurchase_organization_id())
                    .sale_organization_name(invoiceApply.getPurchase_organization_name())
                    .purchase_bank(invoiceApply.getSale_bank())
                    .purchase_account(invoiceApply.getSale_account())
                    .purchase_address(invoiceApply.getSale_address())
                    .purchase_phone(invoiceApply.getSale_phone())
                    .purchase_number(invoiceApply.getSale_number())
                    .purchase_name(invoiceApply.getSale_name())
                    .build();
            viewSettleInvoice.setInvoiceServiceApplyProcess(invoiceServiceApplyProcess);

        }
        //按照ApplyId分组进行展示
        settleInvoiceDetails.stream().collect(Collectors.groupingBy(SettleInvoiceDetail::getApply_id))
                .forEach((groupApplyIdKey, settleInvoiceDetailValue) -> {
                    //根据分组的维度计算可申请金额(writeOffAmount)、总金额(total)、平台费(platform)、垫资费(interest)
                    BigDecimal writeOffAmount = BigDecimal.ZERO,
                            total = BigDecimal.ZERO,
                            platform = BigDecimal.ZERO,
                            interest = BigDecimal.ZERO,
                            platformRates = BigDecimal.ZERO,
                            interestRates = BigDecimal.ZERO;
                    Set<String> numbers = new HashSet<>();

                    for (SettleInvoiceDetail settleInvoiceDetail : settleInvoiceDetailValue) {
                        writeOffAmount = BigDecimalUtils.add(settleInvoiceDetail.getWrite_off_amount(), writeOffAmount);
                        total = BigDecimalUtils.add(settleInvoiceDetail.getTotal(), total);
                        platform = BigDecimalUtils.add(settleInvoiceDetail.getPlatformservicefee(), platform);
                        platformRates = settleInvoiceDetail.getPlatform_rate() == null ? BigDecimal.ZERO : settleInvoiceDetail.getPlatform_rate();
                        interest = BigDecimalUtils.add(settleInvoiceDetail.getInterests(), interest);
                        interestRates = settleInvoiceDetail.getInterest_rate() == null ? BigDecimal.ZERO : settleInvoiceDetail.getInterest_rate();
                        numbers.add(settleInvoiceDetail.getNumber());

                    }

                    Date date = null;
                    if (!CollectionUtils.isEmpty(settleInvoiceDetailValue)) {
                        date = settleInvoiceDetailValue.get(0).getDate();
                    }
                    viewSettleInvoiceDetails.add(SettleInvoiceDetail.builder()
                            .write_off_amount(writeOffAmount)
                            .apply_id(groupApplyIdKey)
                            .total(total)
                            .platformservicefee(platform)
                            .platform_rate(platformRates)
                            .interests(interest)
                            .interest_rate(interestRates)
                            .number(StringUtils.join(numbers, ","))
                            //.settleCustomerStatus(settleCustomerStatus)
                            .date(date)
                            .build());
                });
        viewSettleInvoice.setApply_type(applyQuery.getApply_type());

        BigDecimal platformSum = CalculatorUtils.sum(viewSettleInvoiceDetails, settleInvoiceDetailPlatformFun);
        BigDecimal interestSum = CalculatorUtils.sum(viewSettleInvoiceDetails, settleInvoiceDetailInterestFun);
        viewSettleInvoice.setPlatform(platformSum);
        viewSettleInvoice.setInterest(interestSum);
        return viewSettleInvoice.setSettleInvoiceDetails(viewSettleInvoiceDetails);
    }

    @Override
    public void createPurchaseSettle(SettleInvoice settleInvoice) {
        log.info(">>>>>>>>>开始>>>>>>>创建供应商收款单{}", JSON.toJSONString(settleInvoice));
        settleInvoice.setApply_member_id(RequestContext.getCorpLoginId());
        settleInvoice.setApply_member_name(RequestContext.getLoginRealName());
        verifyCreate(settleInvoice);
        Settle settleEntity = new Settle();
        BeanUtils.copyProperties(settleInvoice, settleEntity);
        settleEntity.setContract(false);
        //settleEntity.setContract_payment_type(ContractPaymentType.Goods);
        //获取可结算发票数据
        SettleInvoice canSettleInvoice = this.getCanApply(SettleApplyQuery.builder().apply_type(settleInvoice.getApply_type()).ids(settleInvoice.getDetailApplyIds()).build());
        Assert.notNull(canSettleInvoice, "未获取可结算发票数据");
        Assert.isTrue(!CollectionUtils.isEmpty(canSettleInvoice.getSettleInvoiceDetails()), "未获取可结算发票数据");
        BigDecimal settleInvoiceDetailAvailable = CalculatorUtils.sum(canSettleInvoice.getSettleInvoiceDetails(), settleInvoiceDetailWriteOffAmountFun);
        Assert.isTrue(settleEntity.getTotal().compareTo(settleInvoiceDetailAvailable) <= 0, "申请金额" + settleEntity.getTotal() + "不能大于可申请金额" + settleInvoiceDetailAvailable);

        Assert.notNull(canSettleInvoice, "无可结算数据");
        Assert.notNull(canSettleInvoice.getNumber(), "提交时未获取可结算的发票号码，请联系管理员");

        //替换英文括号为中文括号
        String purchaseName = settleEntity.getPurchase_name();
        if (null != purchaseName) {
            purchaseName = purchaseName.replace("(", "（").replace(")", "）");
        }
        //从可结算数据中获取采销组织信息和对应的发票号码
        settleEntity.setInvoice_number(canSettleInvoice.getNumber())
                .setSale_organization_id(canSettleInvoice.getSale_organization_id())
                .setSale_organization_name(canSettleInvoice.getSale_organization_name())
                .setPurchase_organization_id(canSettleInvoice.getPurchase_organization_id())
                .setPurchase_organization_name(canSettleInvoice.getPurchase_organization_name())
                .setPurchase_name(purchaseName);
        SettleBusinessType businessType = settleInvoice.getBusiness_type();
        Assert.isTrue(businessType == SettleBusinessType.PurchasePayment, "业务类型必须为采购付款");
        settleEntity.setBusiness_type(businessType);

        List<SettleDetail> settleDetailEntityList = this.buildSettleDetail(canSettleInvoice, settleInvoice.getSettleInvoiceDetails());

        //明细关联的交易
        List<Trade> tradeList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                .in("id", settleDetailEntityList.stream().map(SettleDetail::getTrade_id).collect(Collectors.toList()))
                .queryForPOJOList(Trade.class);
        //明细关联的账单
        List<Bill> billList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                .in("id", settleDetailEntityList.stream().map(SettleDetail::getBill_id).collect(Collectors.toList()))
                .queryForPOJOList(Bill.class);

        //计算采购服务费、垫资费
        BigDecimal settleTotal = BigDecimal.ZERO, platformSum = BigDecimal.ZERO, interestSum = BigDecimal.ZERO;//结算金额
        for (SettleDetail settleDetail : settleDetailEntityList) {
            Trade trade = tradeList.stream().filter(t -> t.getId().equals(settleDetail.getTrade_id())).findAny().get();
            Bill bill = billList.stream().filter(t -> t.getId().equals(settleDetail.getBill_id())).findAny().get();

            //平台费
            BigDecimal platformRate = settleInvoice.getPlatform_rate() == null ? trade.getPlatform_rate() : BigDecimalUtils.div(settleInvoice.getPlatform_rate(), 100);
            Map<String, BigDecimal> platformFeeMap = this.calculationPlatform(platformRate, settleDetail.getTotal());

            //垫资服务费
            boolean repayment = tradeService.isRepayment(trade.getOrder_goods_id(), trade.getDirection());
            Date inquiryTime = DateUtils.strToDate(trade.getExtends_attr().getInquiryTime());
            Map<String, BigDecimal> interestFeeMap = this.calculationPurchasePaymentInterest(bill.getBill_date(), trade.getAccount_period().intValue(),
                    settleDetail.getTotal(), repayment, inquiryTime, settleInvoice.getInterest_rate(), null);
            settleDetail.setInterest(interestFeeMap.get("interestFee")).setInterest_rate(interestFeeMap.get("interestRate"));
            settleDetail.setPlatform(platformFeeMap.get("platformFee")).setPlatform_rate(platformFeeMap.get("platformRate"));
            //金额汇总
            interestSum = BigDecimalUtils.add(interestSum, settleDetail.getInterest());
            platformSum = BigDecimalUtils.add(platformSum, settleDetail.getPlatform());
            settleTotal = settleTotal.add(settleDetail.getTotal()).subtract(interestSum).subtract(platformSum);

        }

        //有服务费则构建服务费发票信息，用于确认付款后创建服务费发票信息
        InvoiceApplyForm serviceInvoice = settleInvoice.getInvoiceServiceApplyProcess();
        if (BigDecimalUtils.add(platformSum, interestSum).compareTo(BigDecimal.ZERO) > 0) {
            //明细关联的发票
            List<InvoiceApply> invoiceApplyList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField("*")
                    .in("id", settleDetailEntityList.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toList()))
                    .queryForPOJOList(InvoiceApply.class);

            InvoiceApply historyInvoice = invoiceApplyList.get(0);
            Assert.notNull(historyInvoice, "获取发票数据异常，发票id：" + settleDetailEntityList.get(0).getInvoice_apply_id());

            verifyInvoiceApplyProcessCreate(serviceInvoice);
            serviceInvoice.setPurchase_organization_id(historyInvoice.getSale_organization_id())
                    .setPurchase_organization_name(historyInvoice.getSale_organization_name())
                    .setSale_organization_id(historyInvoice.getPurchase_organization_id())
                    .setSale_organization_name(historyInvoice.getPurchase_organization_name())
                    .setApply_member_id(RequestContext.getCorpLoginId())
                    .setApply_member_name(RequestContext.getLoginRealName());
        }
        SettleExtendsAttr settleExtendsAttr = SettleExtendsAttr.builder().invoiceApplyProcess(serviceInvoice).build();
        settleEntity.setExtends_attr(JSON.toJSONString(settleExtendsAttr));

        settleEntity.setInterest_rate(settleInvoice.getInterest_rate());
        settleEntity.setPlatform_rate(settleInvoice.getPlatform_rate());
        settleEntity.setInterest(interestSum).setPlatform(platformSum);
        settleEntity.setTotal(settleTotal);
        settleEntity.setRefund_total(BigDecimal.ZERO);
        settleEntity.setWrite_off_total(BigDecimal.ZERO);
        settleEntity.setWoffNow("1");
        settleEntity.setStatuss(SettleStatus.New);
        settleEntity.setApply_time(new Date());
        settleEntity.setPlatform_organization_id(settleEntity.getPurchase_organization_id().getId());

        Map<String, Object> settleMap = settleEntity.beanToMap();
        SingleResponse<BO> bo = BoServiceUtils.createBo(ModelConst.T_SETTLE, Collections.singletonList(settleMap));
        String settleId = bo.getData().getBizObjectId();
        for (SettleDetail settleDetail : settleDetailEntityList) {
            settleDetail.setSettle_id(settleId);
        }
        List<Map<String, Object>> detailMaps = settleDetailEntityList.stream().map(item -> BeanUtil.beanToMap(item)).collect(Collectors.toList());
        BoServiceUtils.createBo(ModelConst.T_SETTLE_DETAIL, detailMaps);
        //回写发票可核销和已核销金额   目前只有保存并提交，回写发票放在提交后
        List<String> invoiceApplyIds = settleDetailEntityList.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toList());
        invoiceApplyService.writeBackInvoiceWriteOffAmountByInvoiceApply(invoiceApplyIds);
        if (settleInvoice.getSubmit()) {
            submit(Collections.singletonList(settleId));
        }

    }

    @Override
    public void approveAgree(List<String> settleIds){
        Assert.isTrue(!CollectionUtils.isEmpty(settleIds), "业务审核通过参数不能为空");
        log.info("采购付款审核ID" + StringUtils.join(settleIds, ','));

        List<Settle> settles = this.loadListByIds(settleIds);
        Assert.isTrue(settles.size() == settleIds.size(), "期望审核的条目和实际审核的条目不同");
        List<SettleDetail> settleDetailEntities = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                .in("settle_id", settleIds)
                .queryForPOJOList(SettleDetail.class);
        Assert.isTrue(!CollectionUtils.isEmpty(settleDetailEntities), "审核时未找到结算明细");

        for (Settle settle : settles) {
            Assert.isTrue(SettleStatus.ApprovingBusiness == settle.getStatuss(), "只能状态为待业务审核才可操作");
            //目前业务审核和财务审核要求联动，所以直接改成“待财务审批付款”
            settle.setStatuss(SettleStatus.Approving);

            List<SettleDetail> settleDetailEntityList = settleDetailEntities.stream().filter(t -> t.getSettle_id().equals(settle.getId())).distinct().collect(Collectors.toList());
            BigDecimal platform = CalculatorUtils.sum(settleDetailEntityList, BiFunctionConst.settleDetailPlatformFun);
            BigDecimal interest = CalculatorUtils.sum(settleDetailEntityList, BiFunctionConst.settleDetailInterestFun);
            //如果是平台采购付款，就要生成对应服务费账单和服务费发票
            if (PlatformConst.PLATFORM_ORGANIZATION_IDS.contains(settle.getPurchase_organization_id().getId())) {
                if (BigDecimalUtils.add(platform, interest).compareTo(BigDecimal.ZERO) > 0) {
                    List<String> serviceFeeBillIds = this.generateServiceFeeBill(settle.getId());
                    if (!CollectionUtils.isEmpty(serviceFeeBillIds)) {
                        settle.setInvoice_service_ids(StringUtils.join(serviceFeeBillIds, ','));
                    }
                }
            }
            BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, settle.beanToMap());
        }
    }

    @Override
    public void submit(Collection<String> settleIds) {
        List<Settle> settleList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .in("id", settleIds)
                .queryForPOJOList(Settle.class);
        Assert.isTrue(settleList.size() == settleIds.size(), "要提交的结算单不存在");

        for (Settle settle : settleList) {
            Assert.isTrue(settle.getStatuss() == SettleStatus.New, "结算单" + settle.getId() + "不是新建状态不可提交");
            //结算单对应明细
            List<SettleDetail> settleDetailList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                    .eq("settle_id", settle.getId())
                    .queryForPOJOList(SettleDetail.class);
            BigDecimal interestSum = BigDecimal.ZERO;
            BigDecimal platformSum = BigDecimal.ZERO;
            //如果结算单创建时间跟提交时间不在同一天，重新计算平台费和垫资费
            if (DateUtils.differentDays(settle.getCreatedTime(), new Date()) > 0) {
                //明细对应账单
                List<Bill> billList = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                        .eq("id", settleDetailList.stream().map(SettleDetail::getBill_id).collect(Collectors.toList()))
                        .queryForPOJOList(Bill.class);
                //明细对应交易
                List<Trade> tradeList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                        .eq("id", settleDetailList.stream().map(SettleDetail::getTrade_id).collect(Collectors.toList()))
                        .queryForPOJOList(Trade.class);
                for (SettleDetail settleDetail : settleDetailList) {
                    Trade trade = tradeList.stream().filter(t -> t.getId().equals(settleDetail.getTrade_id())).findAny().get();
                    Bill bill = billList.stream().filter(t -> t.getId().equals(settleDetail.getBill_id())).findAny().get();
                    //供应商对应客户是否回款
                    boolean repayment = tradeService.isRepayment(trade.getOrder_goods_id(), trade.getDirection());
                    //平台利率，有自定义利率按自定义算，没有则按交易记录的平台利率
                    BigDecimal platformRate = settle.getPlatform_rate() == null ? trade.getPlatform_rate() : BigDecimalUtils.div(settle.getPlatform_rate(), 100);
                    //计算平台费
                    Map<String, BigDecimal> platformFeeMap = this.calculationPlatform(platformRate, settleDetail.getTotal());
                    //计算垫资费
                    Date inquiryTime = DateUtils.strToDate(trade.getExtends_attr().getInquiryTime());
                    Map<String, BigDecimal> interestFeeMap = this.calculationPurchasePaymentInterest(bill.getBill_date(), trade.getAccount_period().intValue(),
                            settleDetail.getTotal(), repayment, inquiryTime, settle.getInterest_rate(), null);
                    settleDetail.setInterest(interestFeeMap.get("interestFee")).setInterest_rate(interestFeeMap.get("interestRate"));
                    settleDetail.setPlatform(platformFeeMap.get("platformFee")).setPlatform_rate(platformFeeMap.get("platformRate"));
                    interestSum = interestSum.add(settleDetail.getInterest());
                    platformSum = platformSum.add(settleDetail.getPlatform());
                }
                //更新结算明细的平台费，垫资费
                List<Map<String, Object>> params = settleDetailList.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());
                BoServiceUtils.updateMainBo(ModelConst.T_SETTLE_DETAIL, params);
                //重新计算结算单付款金额
                BigDecimal settleTotal = CalculatorUtils.sum(settleDetailList, BiFunctionConst.settleDetailTotalFun).subtract(interestSum).subtract(platformSum);
                settle.setTotal(settleTotal).setInterest(interestSum).setPlatform(platformSum);
            }
            String applyMemberId = settle.getApply_member_id();
            UserDto applyMember = UserUtils.getUserByUserId(applyMemberId);
            SettleStatus settleStatus = SettleStatus.Approving;
            if (!PlatformConst.PLATFORM_ORGANIZATION_IDS.contains(applyMember.getOrganization_id().get(0).getId())
                    || (settle.getPlatform_rate()!=null && settle.getInterest_rate()!=null)){
                settleStatus = SettleStatus.ApprovingBusiness;
                log.info("供应商收款管理-采购付款审批-流程purchasePaymentApprov，付款申请id::{}",settle.getId());
                workflowService.startWorkflowInstance("purchasePaymentApprov",settle.getId(), RequestContext.getCorpLoginId(),
                        settle.getSale_organization_id().getId(),true,"","","");
            }

            JdbcTemplateUtils.builder(ModelConst.T_SETTLE)
                    .putFieldAndVal("total", settle.getTotal())
                    .putFieldAndVal("interest", settle.getInterest())
                    .putFieldAndVal("platform", settle.getPlatform())
                    .putFieldAndVal("statuss", settleStatus.name())
                    .eq("id", settle.getId())
                    .update();
            //回写发票可核销和已核销金额
            List<String> invoiceApplyIds = settleDetailList.stream().map(SettleDetail::getInvoice_apply_id).collect(Collectors.toList());
            invoiceApplyService.writeBackInvoiceWriteOffAmountByInvoiceApply(invoiceApplyIds);

            //回写交易
            Set<String> tradeIds = settleDetailList.stream().map(SettleDetail::getTrade_id).collect(Collectors.toSet());
            this.writeBackTrade(tradeIds);
        }

    }

    /**
     * 验证服务费发票信息
     *
     * @param invoiceApplyProcess
     */
    public void verifyInvoiceApplyProcessCreate(InvoiceApplyForm invoiceApplyProcess) {
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getAddress()), "服务费收票地址不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPhone()), "服务费发票收货人电话不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getReceiver()), "服务费发票收货人姓名不能为空");
        Assert.notNull(invoiceApplyProcess.getType(), "服务费发票票据类型不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPurchase_account()), "服务费账号不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPurchase_address()), "服务费开票地址不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPurchase_bank()), "服务费开户行不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPurchase_name()), "服务费发票抬头不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPurchase_number()), "服务费发票税号不能为空");
        Assert.isTrue(StringUtils.isNotBlank(invoiceApplyProcess.getPurchase_phone()), "服务费发票电话不能为空");
    }

    /**
     * 构建结算单明细
     * @param canSettleInvoice 发票剩余可申请结算数据
     * @param settleInvoiceDetails 本次申请结算数据
     * @return
     */
    private List<SettleDetail> buildSettleDetail(SettleInvoice canSettleInvoice, List<SettleInvoiceDetail> settleInvoiceDetails) {
        //构建结算明细
        List<SettleDetail> settleDetailEntityList = new ArrayList<>();

        List<SettleInvoiceDetail> canSettleInvoiceDetailList = canSettleInvoice.getSettleInvoiceDetails();
        //根据applyId分组
        canSettleInvoiceDetailList.stream().collect(Collectors.groupingBy(SettleInvoiceDetail::getApply_id))
                .forEach((applyIdGroupKey, canSettleInvoiceDetailValue) -> {
                    BigDecimal applyRatio = BigDecimal.ONE;
                    //从参数中判断是否需要分批结算
                    List<SettleInvoiceDetail> applySettleInvoiceDetailList = settleInvoiceDetails.stream()
                            .filter(t -> t.getApply_id().equals(applyIdGroupKey)).collect(Collectors.toList());

                    if (!CollectionUtils.isEmpty(applySettleInvoiceDetailList)) {
                        SettleInvoiceDetail applySettleInvoiceDetail = applySettleInvoiceDetailList.get(0);
                        //计算结算比例
                        if (null != applySettleInvoiceDetail.getBatch_total()) {
                            Assert.isTrue(applySettleInvoiceDetail.getBatch_total().compareTo(BigDecimal.ZERO) > 0, "本次结算金额必须大于0");
                            //分批结算需要获取总金额，并计算分批比例(applyRatio)=本次结算金额(batchTotal)/可结算金额(availableTotal)
                            //BigDecimal total = BigDecimal.ZERO;//发票总额
                            BigDecimal availableTotal = BigDecimal.ZERO;//当前发票剩余可申请结算总额
                            for (SettleInvoiceDetail canSettleInvoiceDetail : canSettleInvoiceDetailValue) {
                                //total = BigDecimalUtils.add(canSettleInvoiceDetail.getTotal(), total);
                                availableTotal = BigDecimalUtils.add(canSettleInvoiceDetail.getWrite_off_amount(), availableTotal);
                            }

                            Assert.isTrue(availableTotal.compareTo(BigDecimal.ZERO) > 0, "发票编号" + applyIdGroupKey + " 无可结算金额");
                            applyRatio = BigDecimalUtils.div(applySettleInvoiceDetail.getBatch_total(), availableTotal);
                            if (applyRatio.compareTo(BigDecimal.ONE) > 1) {
                                applyRatio = BigDecimal.ONE;
                            }
                        }

                        //构建以账单维度的结算明细
                        int i = 0;
                        BigDecimal applyTotal = BigDecimal.ZERO;//分批申请总额
                        for (SettleInvoiceDetail settleInvoiceDetail : canSettleInvoiceDetailValue) {
                            BigDecimal availableTotal = settleInvoiceDetail.getWrite_off_amount();

                            //分批四舍五入可能会有小数位差，最后一次需要拿分批金额减已申请金额
                            if (applyRatio.compareTo(BigDecimal.ONE) != 1 && i == canSettleInvoiceDetailValue.size() - 1) {
                                //最后一次减回去
                                availableTotal = BigDecimalUtils.sub(applySettleInvoiceDetail.getBatch_total(), applyTotal);
                            } else {
                                availableTotal = BigDecimalUtils.round(BigDecimalUtils.mul(availableTotal, applyRatio), 2);
                                applyTotal = BigDecimalUtils.add(availableTotal, applyTotal);
                            }

                            //获取账单的商品扩展信息
                            Bill billEntity = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                                    .eq("id", settleInvoiceDetail.getBill_id())
                                    .queryForPOJO(Bill.class);
                            String extendsAttr = "";
                            if (!ObjectUtils.isEmpty(billEntity)) {
                                extendsAttr = billEntity.getSummary();
                            }

                            settleDetailEntityList.add(SettleDetail.builder()
                                    .bill_id(settleInvoiceDetail.getBill_id())
                                    .total(availableTotal)
                                    .invoice_apply_id(settleInvoiceDetail.getInvoice_apply_id())
                                    .invoice_detail_bill_id(settleInvoiceDetail.getInvoice_detail_bill_id())
                                    .trade_id(settleInvoiceDetail.getTrade_id())
                                    .name(settleInvoiceDetail.getName())
                                    .platform(BigDecimal.ZERO)
                                    .interest(BigDecimal.ZERO)
                                    .other(BigDecimal.ZERO)
                                    .model_spec(settleInvoiceDetail.getModel_spec())
                                    .extends_attr(extendsAttr)
                                    .build());
                            i++;
                        }
                    }
                });

        return settleDetailEntityList;
    }

    /**
     * 获取申请收款记录的收款明细
     * @param applyQuery
     * @return
     */
    private SettleInvoice getCanApply(SettleApplyQuery applyQuery) {
        log.info(">>>>>>>>>开始>>>>>>获取结算单可核销数据，入参：{}", JSON.toJSONString(applyQuery));
        //1、根据不同的ID类型获取对应账单维度可结算的发票数据
        SettleInvoice settleInvoice = invoiceDetailBillService.getSettleInvoice(applyQuery.getApply_type(), applyQuery.getIds());
        Assert.notNull(settleInvoice, "未获取到可结算的发票数据");
        //2、账单已申请结算的部分
        List<String> billIds = settleInvoice.getSettleInvoiceDetails().stream().map(SettleInvoiceDetail::getBill_id).distinct().collect(Collectors.toList());
        StringBuffer sql = new StringBuffer()
                .append(" select detail.bill_id billId,detail.total total,invoice_apply_id from " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE_DETAIL) + " detail \n")
                .append(" left join " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE) + " settle on settle.id=detail.settle_id  ")
                .append(" where detail.deleted=0 and settle.deleted=0 and settle.status<>'Returned' and (business_type = 'PurchasePayment' or business_type = 'SaleReceivable')")
                .append("  and bill_id in (:billIds)");
        Map<String, Object> params = MapBuilder.create(new HashMap<String, Object>())
                .put("billIds", billIds)
                .build();
        List<SettleDetail> settleDetailList = JdbcTemplateUtils.queryForPOJOList(sql.toString(), params, ModelConst.T_SETTLE_DETAIL, SettleDetail.class);

        if (applyQuery.getApply_type() == SettleApplyType.Invoice) {
            settleDetailList = settleDetailList.stream().filter(t -> applyQuery.getIds().contains(t.getInvoice_apply_id())).collect(Collectors.toList());
        }
        List<SettleDetail> results = new ArrayList<>();//已结算的账单维度明细
        for (String billId : billIds) {
            List<SettleDetail> billSettleDetails = settleDetailList.stream().filter(t -> t.getBill_id().equals(billId)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(billSettleDetails)) {
                results.add(SettleDetail.builder().bill_id(billId).total(BigDecimal.ZERO).build());
                continue;
            }
            BigDecimal total = BigDecimal.ZERO;
            for (SettleDetail billSettleDetail : billSettleDetails) {
                total = BigDecimalUtils.add(billSettleDetail.getTotal(), total);
            }
            results.add(SettleDetail.builder().bill_id(billId).total(total).build());
        }

        //计算可申请结算金额=账单已开票金额-已申请结算金额(因为结算明细要关联发票申请单ID，所以可能会出现多条相同账单ID的发票明细,循环减去已结算金额时保证同一账单多条申请明细的计算正确性)
        settleInvoice.getSettleInvoiceDetails().stream().collect(Collectors.groupingBy(SettleInvoiceDetail::getBill_id))
                .forEach((billIdKey, canSettleInvoiceDetailsValue) -> {
                    SettleDetail appliedSettle = results.stream().filter(t -> t.getBill_id().equals(billIdKey)).collect(Collectors.toList()).get(0);
                    //已申请结算金额
                    BigDecimal haveAppliedSettledTotal = appliedSettle.getTotal();
                    for (SettleInvoiceDetail canSettleInvoiceDetail : canSettleInvoiceDetailsValue) {
                        //可申请金额=总可申请金额-已经申请金额
                        BigDecimal canApplyTotal = BigDecimalUtils.sub(canSettleInvoiceDetail.getBill_total(), haveAppliedSettledTotal);
                        //如果可申请结算金额>已开票的账单金额，以开票金额为申请金额
                        if (canApplyTotal.compareTo(BigDecimal.ZERO) != 0
                                && canSettleInvoiceDetail.getTotal().abs().compareTo(canApplyTotal.abs()) == -1) {
                            canApplyTotal = canSettleInvoiceDetail.getTotal();
                        }
                        canSettleInvoiceDetail.setWrite_off_amount(canApplyTotal);
                        haveAppliedSettledTotal = BigDecimalUtils.add(haveAppliedSettledTotal, canApplyTotal);
                    }
                });
        log.info(">>>>>>>>>结束>>>>>>获取获取结算单可核销数据，返回：{}", JSON.toJSONString(settleInvoice));
        return settleInvoice;

    }

    /**
     * 根据结算单申请时的明细计算服务费（平台费、垫资费）赋值对应的结算字段
     *
     * @param details           结算单明细实体列表（用到tradeId列表，计算平台费和客户回款状态）
     * @param bills             可结算的账单列表（计算垫资费）
     * @param interestRate      自定义垫资服务费结算比例
     * @param platformRate      自定义平台服务费结算比例
     * @param originalApplyDate 原结算单的申请时间（采购付款，重新核销时使用）
     */
    private void getCanApplyServiceFee(@NonNull List<SettleInvoiceDetail> details, @NonNull List<Bill> bills,
                                       BigDecimal interestRate, BigDecimal platformRate, Date originalApplyDate) {

        List<String> tradeIds = details.stream().map(SettleInvoiceDetail::getTrade_id).collect(Collectors.toList());
        Assert.isTrue(!CollectionUtils.isEmpty(tradeIds), "结算明细中未获取到交易ID列表");
        List<Trade> trades = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                .in("id", tradeIds)
                .queryForPOJOList(Trade.class);
        for (SettleInvoiceDetail settleInvoiceDetail : details) {
            List<Trade> mappingTrades = trades.stream().filter(t -> t.getId().equals(settleInvoiceDetail.getTrade_id())).collect(Collectors.toList());
            Assert.isTrue(!mappingTrades.isEmpty(), "从交易获取服务费费率异常");

            Trade trade = mappingTrades.get(0);
            Map<String, BigDecimal> platformMap = calculationPlatform(null == platformRate ? trade.getPlatform_rate() : BigDecimalUtils.div(platformRate, 100),
                    settleInvoiceDetail.getWrite_off_amount());

            //客户回款状态
            boolean repayment = tradeService.isRepayment(trade.getTarget_order_goods_id(), TradeDirection.Sale.name());

            Date inquiryTime = DateUtils.strToDate(trade.getExtends_attr().getInquiryTime());

            Bill bill = bills.stream().filter(t -> t.getId().equals(settleInvoiceDetail.getBill_id())).collect(Collectors.toList()).get(0);
            Map<String, BigDecimal> interestMap = calculationPurchasePaymentInterest(bill.getBill_date(), trade.getAccount_period().intValue(), settleInvoiceDetail.getWrite_off_amount(),
                    repayment, inquiryTime, interestRate, originalApplyDate);

            settleInvoiceDetail.setInterests(interestMap.get("interestFee"))
                    .setInterest_rate(interestMap.get("interestRate"))
                    .setPlatformservicefee(platformMap.get("platformFee"))
                    .setPlatform_rate(platformMap.get("platformRate"));
        }
    }

    /**
     * 根据交易id查询结算完成的金额
     *
     * @param tradeId 交易ID
     * @return 结算完成的金额
     */
    @Override
    public  BigDecimal completedStatusSettle(String tradeId){
        String sql = "SELECT IFNULL(sum(A.total),0) from "+ JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE_DETAIL) +
                " A LEFT JOIN " + JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE) + " B on A.settle_id=B.id  " +
                "WHERE A.deleted = 0 AND A.trade_id='"+tradeId+"'  and B.status='Done' ";
        return jdbcTemplate.queryForObject(sql, new HashMap<>(), BigDecimal.class);
    }

    @NotNull
    private Map<String, BigDecimal> calculationPlatform(BigDecimal platformRate, BigDecimal available_total) {
        Assert.isTrue(platformRate.compareTo(BigDecimal.ZERO) >= 0 && platformRate.compareTo(BigDecimal.ONE) <= 0, "平台费率只能是0-100%");
        BigDecimal platformFee = BigDecimal.ZERO;
        if (platformRate.compareTo(BigDecimal.ZERO) != 0) {
            platformFee = BigDecimalUtils.mul(available_total, platformRate).setScale(2, RoundingMode.HALF_UP);
        }
        return MapBuilder.create(new HashMap<String, BigDecimal>()).put("platformFee", platformFee).put("platformRate", platformRate).build();
    }

    /**
     * 计算采购付款垫资费
     *
     * @param billTime          账单创建时间(账期开始时间)
     * @param accountPeriod     账期
     * @param applyTotal        申请金额
     * @param repayment         回款状态（客户未付款完成,供应商发起了收款,计算当前时间是账期后收款还是账期前,如果账期前就按正常流程走,如果账期后则按照账期前一样承担账期费用）
     * @param inquiryTime       询价时间
     * @param interestRate      自定义垫资费结算比例
     * @param originalApplyTime 原结算单的申请时间（采购付款，重新核销时使用）
     * @return 垫资费
     */
    private Map<String, BigDecimal> calculationPurchasePaymentInterest(Date billTime, int accountPeriod, BigDecimal applyTotal, boolean repayment,
                                                                       Date inquiryTime, BigDecimal interestRate, Date originalApplyTime) {
        BigDecimal interestFee = BigDecimal.ZERO;

        //计算当前日期和账期开始点之间的天数，是为了判断是否小于账期天数，如果小于需要进行垫资费计算
        Date currentTime = new Date();

        //如果取消重新核销，需要取原结算单的申请时间
        if (null != originalApplyTime) {
            currentTime = originalApplyTime;
        }
        LocalDate billLocalDate = billTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Date interestStartTime = Date.from(billLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        long time = currentTime.getTime() / 1000 - interestStartTime.getTime() / 1000;
        int day = (int) BigDecimalUtils.div(new BigDecimal(time), new BigDecimal(3600 * 24)).doubleValue();

        BigDecimal interestRates = BigDecimal.ZERO;

        if (null == interestRate) {
            //客户未回款，或者当前时间跟账单时间的差额小于账期则计算垫资服务费
            if (!repayment || day <= accountPeriod) {
                double days = accountPeriod / 30.0;
                interestRates = BigDecimalUtils.div(new BigDecimal(Math.ceil(days)), new BigDecimal(100));
                if (inquiryTime.after(DateUtils.strToDate(PlatformConst.INTEREST_CHANGE_POINT))) {
                    interestRates = interestRates.multiply(new BigDecimal("1.5"));
                }
                interestFee = applyTotal.multiply(interestRates).setScale(2, RoundingMode.HALF_UP);
            }
        } else {
            Assert.isTrue(interestRate.compareTo(BigDecimal.ZERO) >= 0 && interestRate.compareTo(new BigDecimal("100")) <= 0, "垫资费结算比例只能是0-100%");
            interestRates = BigDecimalUtils.div(interestRate, new BigDecimal("100"));
            interestFee = BigDecimalUtils.mul(applyTotal, interestRates);
            interestFee = BigDecimalUtils.round(interestFee, 2);
        }
        return MapBuilder.create(new HashMap<String, BigDecimal>()).put("interestFee", interestFee).put("interestRate", interestRates).build();
    }

    /**
     * 获取结算单的可核销金额(根据有效的结算明细)
     * 可核销金额= 结算单 -退款 -已核销
     * @param settleId 结算单ID
     * @return 除去退款、已核销部分的可核销金额
     */
    private BigDecimal getSettleWriteOffAmount(String settleId) {
        Assert.notNull(settleId, "计算可核销金额参数不能为空");
        Settle settle = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .eq("id", settleId).queryForPOJO(Settle.class);

        Assert.notNull(settle, "未获取到计算结算单可核销金额的结算单");
        //获取该结算单的已核销金额，为了准确，用明细计算
        Map<String, Object> amountMap = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL)
                .selectField(" IFNULL(SUM(total), 0) settleDetailTotalAmount, IFNULL(SUM(interest), 0) settleDetailInterestAmount,IFNULL(SUM(platform), 0) settleDetailPlatformAmount ")
                .eq("deleted", 0)
                .eq("settle_id", settleId).queryForMap();
        BigDecimal settleDetailTotalAmount = new BigDecimal(amountMap.get("settleDetailTotalAmount").toString());
        BigDecimal settleDetailInterestAmount = new BigDecimal(amountMap.get("settleDetailInterestAmount").toString());
        BigDecimal settleDetailPlatformAmount = new BigDecimal(amountMap.get("settleDetailPlatformAmount").toString());

        //明细的total是包含服务费的，需要减去服务费才是实际金额
        BigDecimal settleAmout = settleDetailTotalAmount.subtract(settleDetailInterestAmount).subtract(settleDetailPlatformAmount);

        //获取该结算单的所有退款单总金额
        BigDecimal settleRefundTotalAmount = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField(" ifnull(sum(total), 0) ")
                .notEq("statuss", SettleStatus.Returned.name())
                .eq("reference_id", settleId).queryForObject(BigDecimal.class);

        //可核销金额= 结算单 -退款 -已核销
        return settle.getTotal().subtract(settleRefundTotalAmount).subtract(settleAmout);
    }

    /**
     * 更新结算单对应交易记录的可结算金额（交易金额-反向金额-已完成金额）
     *
     * @param settleEntity
     */
    private void updateTradeAllowSettleAmount(Settle settleEntity) {
        //根据结算单获取结算明细
        List<SettleDetail> settleDetailEntityList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField(" * ")
                .eq("settle_id", settleEntity.getId())
                .queryForPOJOList(SettleDetail.class);

        if (!CollectionUtils.isEmpty(settleDetailEntityList)) {
            //结算包含的交易记录
            List<String> tradeIdList = settleDetailEntityList.stream().map(SettleDetail::getTrade_id).distinct().collect(Collectors.toList());

            List<SettleDetail> settleDetailEntityAllList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField(" * ")
                    .in("trade_id", tradeIdList)
                    .queryForPOJOList(SettleDetail.class);


            //结算单类型businessType为：SaleReceivable和PurchasePayment为正向
            Map<String, Object> param = new HashMap<>();
            settleDetailEntityAllList.stream().collect(Collectors.groupingBy(SettleDetail::getTrade_id))
                    .forEach((tradeIdKey, settleDetailEntityValue) -> {
                        //已结算金额
                        BigDecimal tradeSettleDetailTotal = BigDecimal.ZERO;
                        for (SettleDetail settleDetailEntity : settleDetailEntityValue) {
                            Settle settleEn = this.loadById(settleDetailEntity.getSettle_id());

                            if (settleEntity.getStatuss() != SettleStatus.Done) {
                                continue;
                            }
                            //正向-负向获取可结算金额
                            if (SettleBusinessType.SaleReceivable.name().equals(settleEn.getBusiness_type())
                                    || SettleBusinessType.PurchasePayment.name().equals(settleEn.getBusiness_type())) {
                                tradeSettleDetailTotal = BigDecimalUtils.add(tradeSettleDetailTotal, settleDetailEntity.getTotal());
                            } else {
                                tradeSettleDetailTotal = BigDecimalUtils.sub(tradeSettleDetailTotal, settleDetailEntity.getTotal());
                            }
                        }

                        Assert.isTrue(tradeSettleDetailTotal.compareTo(BigDecimal.ZERO) >= 0, "正反向交易交易计算异常");

                        //更新交易可结算金额
                        param.clear();
                        param.put("id", tradeIdKey);
                        param.put("allowed_settle_amount", tradeSettleDetailTotal);
                        BoServiceUtils.updateMainBo(ModelConst.T_TRADE, param);

                    });
        }
    }

    /**
     * 结算单已退款金额，统计待财务审核和已付款的退款单总额
     *
     * @param settleId 原结算单号
     */
    private BigDecimal getSettleRefundTotal(String settleId) {
        Settle settle = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .eq("id", settleId)
                .queryForPOJO(Settle.class);
        Assert.notNull(settle, "未获取到" + settleId + "对应的收款单");

        List<Settle> settleList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField("*")
                .eq("reference_id", settleId)
                .in("statuss", Arrays.asList(SettleStatus.Done.name(), SettleStatus.Approving.name()))
                .queryForPOJOList(Settle.class);
        BigDecimal refundTotal = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(settleList)) {
            refundTotal = CalculatorUtils.sum(settleList, BiFunctionConst.settleTotalFun);
//            Map<String, Object> param = new HashMap<>();
//            param.put("id", settleId);
//            param.put("refund_total", refundTotal);
//            BoServiceUtils.updateMainBo(ModelConst.T_SETTLE, param);
        }
        return refundTotal;
    }

    /**
     * 调用点
     * 1、采购付款单确认付款
     * 2、销售结算单(代购)核销，采购结算单重新核销
     * 根据结算单明细生成垫资服务费账单和平台费账单，以及对应发票信息
     *
     * @param settleId 采购付款结算单ID
     * @return 服务费发票ID
     */
    @Override
    public List<String> generateServiceFeeBill(String settleId) {
        Settle settle = JdbcTemplateUtils.builder(ModelConst.T_SETTLE).selectField(" * ")
                .eq("id", settleId)
                .queryForPOJO(Settle.class);
        Assert.notNull(settle, settleId + "付款结算单未找到");

        List<SettleDetail> settleDetailList = JdbcTemplateUtils.builder(ModelConst.T_SETTLE_DETAIL).selectField("*")
                .eq("settle_id", settleId)
                .queryForPOJOList(SettleDetail.class);

        List<Bill> serviceBills = new ArrayList<>();
        for (SettleDetail settleDetail : settleDetailList) {
            if (settleDetail.getPlatform().compareTo(BigDecimal.ZERO) == 1) {
                List<Bill> platServiceBill = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                        .eq("reference_id", settleDetail.getId())
                        .eq("type", BillType.PlatformFee)
                        .queryForPOJOList(Bill.class);
                //没有生成过平台费，则生成
                if (CollectionUtils.isEmpty(platServiceBill)) {
                    //平台费账单
                    serviceBills.add(Bill.builder()
                            .target_id(settleDetail.getBill_id())
                            .type(BillType.PlatformFee.name())
                            .total(settleDetail.getPlatform())
                            .reference_id(settleDetail.getId())
                            .build());
                }
            }
            if (settleDetail.getInterest().compareTo(BigDecimal.ZERO) == 1) {
                List<Bill> interestServiceBill = JdbcTemplateUtils.builder(ModelConst.T_BILL).selectField("*")
                        .eq("reference_id", settleDetail.getId())
                        .eq("type", BillType.FinancialFee)
                        .queryForPOJOList(Bill.class);
                //没有生成过金融服务费，则生成
                if (CollectionUtils.isEmpty(interestServiceBill)) {
                    //金融服务费
                    serviceBills.add(Bill.builder()
                            .target_id(settleDetail.getBill_id())
                            .type(BillType.FinancialFee.name())
                            .total(settleDetail.getInterest())
                            .reference_id(settleDetail.getId())
                            .build());
                }
            }
        }
        if (serviceBills.size() == 0) {
            return null;
        }
        //创建服务费账单
        List<String> serviceBillIds = billService.createServiceBill(serviceBills);

        //创建服务费发票
        List<String> serviceFeeInvoiceIds = this.generateServiceFeeInvocie(settle, serviceBillIds);

        return serviceFeeInvoiceIds;
    }

    /**
     * 构建服务费发票信息
     *
     * @param settle         结算单
     * @param serviceBillIds 服务费账单ID
     * @return
     */
    private List<String> generateServiceFeeInvocie(Settle settle, List<String> serviceBillIds) {
        String extendsAttr = settle.getExtends_attr();
        InvoiceApplyForm invoiceApplyForm = null;
        if (SettleBusinessType.PurchasePayment.name().equals(settle.getBusiness_type()) && null != extendsAttr && !"".equals(extendsAttr)) {
            try {
                //获取扩展字段的申请发票信息
                SettleExtendsAttr extendsObj = JSONObject.parseObject(settle.getExtends_attr(), SettleExtendsAttr.class);
                invoiceApplyForm = extendsObj.getInvoiceApplyProcess();

                Assert.notNull(invoiceApplyForm, "服务费发票信息数据转换失败");
            } catch (Exception e) {
                log.error("通过结算单货物服务费发票信息转换失败", e);
                Assert.isTrue(false, "通过结算单货物服务费发票信息转换失败");
            }

            List<ApplyInvoiceDetailDto> invoiceDetailList = new ArrayList<>();
            serviceBillIds.forEach(t -> invoiceDetailList.add(ApplyInvoiceDetailDto.builder().id(t).build()));

            invoiceApplyForm.setInvoiceCreationWays(OriginIDType.Bill)
                    .setBusiness_type(InvoiceBusinessType.Service.name())
                    .setDirection(TradeDirection.Purchase.name())
                    .setApplyInvoiceDetailDtoList(invoiceDetailList);
        } else {
            if (settle.isContract()) {
                //获取客户发票信息，当做服务费发票信息
                Assert.notNull(settle.getInvoice_number(), "发票号码不能为空");
                List<InvoiceApply> invoiceApplyEntityList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField(" * ")
                        .eq("number", settle.getInvoice_number())
                        .queryForPOJOList(InvoiceApply.class);
                Assert.isTrue(!CollectionUtils.isEmpty(invoiceApplyEntityList), "创建服务费发票时未获取到对应发票信息");

                List<ApplyInvoiceDetailDto> invoiceDetailList = new ArrayList<>();
                serviceBillIds.forEach(t -> invoiceDetailList.add(ApplyInvoiceDetailDto.builder().id(t).build()));


                InvoiceApply invoiceApplyEntity = invoiceApplyEntityList.get(0);
                invoiceApplyForm = invoiceApplyForm.builder()
                        .submit(true)
                        .type(InvoiceType.VatSpecial.name())
                        .purchase_name(invoiceApplyEntity.getPurchase_name())
                        .purchase_number(invoiceApplyEntity.getPurchase_number())
                        .purchase_address(invoiceApplyEntity.getPurchase_address())
                        .purchase_phone(invoiceApplyEntity.getPurchase_phone())
                        .purchase_bank(invoiceApplyEntity.getPurchase_bank())
                        .purchase_account(invoiceApplyEntity.getPurchase_account())
                        .receiver(invoiceApplyEntity.getReceiver())
                        .address(invoiceApplyEntity.getAddress())
                        .phone(invoiceApplyEntity.getPhone())
                        .apply_member_id(settle.getApply_member_id())
                        .apply_member_name(settle.getApply_member_name())
                        .purchase_organization_id(invoiceApplyEntity.getPurchase_organization_id())
                        .purchase_organization_name(invoiceApplyEntity.getPurchase_organization_name())
                        .sale_organization_id(invoiceApplyEntity.getSale_organization_id())
                        .sale_organization_name(invoiceApplyEntity.getSale_organization_name())
                        .invoiceCreationWays(OriginIDType.Bill)
                        .business_type(InvoiceBusinessType.Service.name())
                        .applyInvoiceDetailDtoList(invoiceDetailList)
                        .trade_order_type(TradeOrderType.Agent.name())
                        .direction(TradeDirection.Sale.name())
                        .build();
            }
        }

        if (invoiceApplyForm != null) {
            //创建服务费发票
            List<String> serviceInvoiceApplyIds = invoiceApplyService.createServiceInvoice(Collections.singletonList(invoiceApplyForm));
            invoiceApplyService.submit(serviceInvoiceApplyIds);
            return serviceInvoiceApplyIds;
        } else {
            return null;
        }
    }

    public void verifyCreate(SettleInvoice settleInvoice) {
        Assert.notNull(settleInvoice.getTotal(), "收款金额不能为空");
        Assert.notNull(settleInvoice.getSale_organization_id(), "收款结算组织ID不能为空，请检查是否已维护结算组织");
        Assert.isTrue(settleInvoice.getSale_organization_name() != null && !"".equals(settleInvoice.getSale_organization_name()), "收款结算组织不能为空");
        Assert.notNull(settleInvoice.getPurchase_organization_id(), "付款结算组织组织ID不能为空，请检查是否已维护结算组织");
        Assert.isTrue(settleInvoice.getPurchase_organization_name() != null && !"".equals(settleInvoice.getPurchase_organization_name()), "付款结算组织不能为空");
        Assert.isTrue(settleInvoice.getTotal().compareTo(BigDecimal.ZERO) > 0, "收款金额不正确：" + settleInvoice.getTotal());
        Assert.isTrue(!settleInvoice.getSale_organization_id().equals(settleInvoice.getPurchase_organization_id()), "付款组织和收款组织不能相同");
        Assert.notNull(settleInvoice.getBusiness_type(), "结算业务类型不能为空");
        Assert.notNull(settleInvoice.getType(), "支付类型不能为空");
        Assert.isTrue(null != settleInvoice.getApply_member_id()
                && RegexUtils.notNull(settleInvoice.getApply_member_name()), "申请人信息不能为空");
        Assert.isTrue(RegexUtils.notNull(settleInvoice.getSale_bank_info()), "收款开户行不能为空");
        Assert.isTrue(RegexUtils.notNull(settleInvoice.getSale_bank_no()), "收款账号不能为空");
        Assert.isTrue(RegexUtils.notNull(settleInvoice.getSale_bank_account()), "收款账户名不能为空");
        Assert.isTrue(RegexUtils.notNull(settleInvoice.getSale_phone()), "收款联系电话不能为空");
    }
}
